diff options
Diffstat (limited to 'libcutl/cutl/compiler')
-rw-r--r-- | libcutl/cutl/compiler/code-stream.hxx | 154 | ||||
-rw-r--r-- | libcutl/cutl/compiler/code-stream.txx | 95 | ||||
-rw-r--r-- | libcutl/cutl/compiler/context.cxx | 54 | ||||
-rw-r--r-- | libcutl/cutl/compiler/context.hxx | 137 | ||||
-rw-r--r-- | libcutl/cutl/compiler/context.txx | 88 | ||||
-rw-r--r-- | libcutl/cutl/compiler/cxx-indenter.cxx | 49 | ||||
-rw-r--r-- | libcutl/cutl/compiler/cxx-indenter.hxx | 171 | ||||
-rw-r--r-- | libcutl/cutl/compiler/cxx-indenter.ixx | 69 | ||||
-rw-r--r-- | libcutl/cutl/compiler/cxx-indenter.txx | 817 | ||||
-rw-r--r-- | libcutl/cutl/compiler/sloc-counter.hxx | 78 | ||||
-rw-r--r-- | libcutl/cutl/compiler/sloc-counter.txx | 224 | ||||
-rw-r--r-- | libcutl/cutl/compiler/traversal.hxx | 171 | ||||
-rw-r--r-- | libcutl/cutl/compiler/traversal.txx | 144 | ||||
-rw-r--r-- | libcutl/cutl/compiler/type-id.hxx | 48 | ||||
-rw-r--r-- | libcutl/cutl/compiler/type-id.ixx | 44 | ||||
-rw-r--r-- | libcutl/cutl/compiler/type-id.txx | 17 | ||||
-rw-r--r-- | libcutl/cutl/compiler/type-info.cxx | 30 | ||||
-rw-r--r-- | libcutl/cutl/compiler/type-info.hxx | 111 | ||||
-rw-r--r-- | libcutl/cutl/compiler/type-info.ixx | 95 |
19 files changed, 2596 insertions, 0 deletions
diff --git a/libcutl/cutl/compiler/code-stream.hxx b/libcutl/cutl/compiler/code-stream.hxx new file mode 100644 index 0000000..bfd33d0 --- /dev/null +++ b/libcutl/cutl/compiler/code-stream.hxx @@ -0,0 +1,154 @@ +// file : cutl/compiler/code-stream.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_CODE_STREAM_HXX +#define CUTL_COMPILER_CODE_STREAM_HXX + +#include <memory> // std::auto_ptr +#include <ostream> + +#include <cutl/exception.hxx> + +namespace cutl +{ + namespace compiler + { + // + // + template <typename C> + class code_stream + { + public: + code_stream () {} + + virtual + ~code_stream (); + + public: + virtual void + put (C) = 0; + + // Unbuffer flushes internal formatting buffers (if any). + // Note that unbuffer is not exactly flushing since it can + // result in formatting errors and in general can not be + // called at arbitrary points. Natural use case would be + // to call unbuffer at the end of the stream when no more + // data is expected. + // + virtual void + unbuffer () = 0; + + private: + code_stream (code_stream const&); + + code_stream& + operator= (code_stream const&); + }; + + // + // + template <typename C> + class from_streambuf_adapter: public code_stream<C> + { + public: + typedef typename std::basic_streambuf<C>::traits_type traits_type; + typedef typename std::basic_streambuf<C>::int_type int_type; + + class eof: exception {}; + class sync: exception {}; + + public: + from_streambuf_adapter (std::basic_streambuf<C>& stream) + : stream_ (stream) + { + } + + private: + from_streambuf_adapter (from_streambuf_adapter const&); + + from_streambuf_adapter& + operator= (from_streambuf_adapter const&); + + public: + virtual void + put (C c); + + virtual void + unbuffer (); + + private: + std::basic_streambuf<C>& stream_; + }; + + // + // + template <typename C> + class to_streambuf_adapter: public std::basic_streambuf<C> + { + public: + typedef typename std::basic_streambuf<C>::traits_type traits_type; + typedef typename std::basic_streambuf<C>::int_type int_type; + + public: + to_streambuf_adapter (code_stream<C>& stream) + : stream_ (stream) + { + } + + private: + to_streambuf_adapter (to_streambuf_adapter const&); + + to_streambuf_adapter& + operator= (to_streambuf_adapter const&); + + public: + virtual int_type + overflow (int_type i); + + // Does nothing since calling unbuffer here would be dangerous. + // See the note in code_stream. + // + virtual int + sync (); + + private: + code_stream<C>& stream_; + }; + + // + // + template <template <typename> class S, typename C> + class ostream_filter + { + public: + typedef S<C> stream_type; + + ostream_filter (std::basic_ostream<C>& os); + ~ostream_filter (); + + stream_type& + stream () + { + return stream_; + } + + private: + ostream_filter (ostream_filter const&); + + ostream_filter& + operator= (ostream_filter const&); + + private: + std::basic_ostream<C>& os_; + std::basic_streambuf<C>* prev_; + from_streambuf_adapter<C> from_adapter_; + stream_type stream_; + to_streambuf_adapter<C> to_adapter_; + }; + } +} + +#include <cutl/compiler/code-stream.txx> + +#endif // CUTL_COMPILER_CODE_STREAM_HXX diff --git a/libcutl/cutl/compiler/code-stream.txx b/libcutl/cutl/compiler/code-stream.txx new file mode 100644 index 0000000..232c5cc --- /dev/null +++ b/libcutl/cutl/compiler/code-stream.txx @@ -0,0 +1,95 @@ +// file : cutl/compiler/code-stream.txx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + // code_stream + // + + template <typename C> + code_stream<C>::~code_stream () + { + } + + // from_streambuf_adapter + // + + template <typename C> + void from_streambuf_adapter<C>:: + put (C c) + { + int_type i (stream_.sputc (c)); + + if (i == traits_type::eof ()) + throw eof (); + } + + template <typename C> + void from_streambuf_adapter<C>:: + unbuffer () + { + if (stream_.pubsync () != 0) + throw sync (); + } + + // to_streambuf_adapter + // + + template <typename C> + typename to_streambuf_adapter<C>::int_type to_streambuf_adapter<C>:: + overflow (int_type i) + { + try + { + stream_.put (traits_type::to_char_type (i)); + return i; + } + catch (typename from_streambuf_adapter<C>::eof const&) + { + return traits_type::eof (); + } + } + + template <typename C> + int to_streambuf_adapter<C>:: + sync () + { + return 0; + } + + // ostream_filter + // + + template <template <typename> class S, typename C> + ostream_filter<S, C>:: + ostream_filter (std::basic_ostream<C>& os) + : os_ (os), + prev_ (os_.rdbuf ()), + from_adapter_ (*prev_), + stream_ (from_adapter_), + to_adapter_ (stream_) + { + os_.rdbuf (&to_adapter_); + } + + template <template <typename> class S, typename C> + ostream_filter<S, C>:: + ~ostream_filter () + { + try + { + stream_.unbuffer (); + } + catch (...) + { + os_.rdbuf (prev_); + throw; + } + + os_.rdbuf (prev_); + } + } +} diff --git a/libcutl/cutl/compiler/context.cxx b/libcutl/cutl/compiler/context.cxx new file mode 100644 index 0000000..51311fc --- /dev/null +++ b/libcutl/cutl/compiler/context.cxx @@ -0,0 +1,54 @@ +// file : cutl/compiler/context.cxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include <cutl/compiler/context.hxx> + +using namespace std; + +namespace cutl +{ + namespace compiler + { + void context:: + set (string const& key, container::any const& value) + { + using container::any; + + std::pair<map::iterator, bool> r ( + map_.insert (map::value_type (key, value))); + + any& x (r.first->second); + + if (!r.second) + { + if (value.type_info () != x.type_info ()) + throw typing (); + + x = value; + } + } + + void context:: + remove (string const& key) + { + map::iterator i (map_.find (key)); + + if (i == map_.end ()) + throw no_entry (); + + map_.erase (i); + } + + type_info const& context:: + type_info (string const& key) const + { + map::const_iterator i (map_.find (key)); + + if (i == map_.end ()) + throw no_entry (); + + return i->second.type_info (); + } + } +} diff --git a/libcutl/cutl/compiler/context.hxx b/libcutl/cutl/compiler/context.hxx new file mode 100644 index 0000000..2933e36 --- /dev/null +++ b/libcutl/cutl/compiler/context.hxx @@ -0,0 +1,137 @@ +// file : cutl/compiler/context.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_CONTEXT_HXX +#define CUTL_COMPILER_CONTEXT_HXX + +#include <map> +#include <string> +#include <cstddef> // std::size_t +#include <typeinfo> + +#include <cutl/exception.hxx> +#include <cutl/container/any.hxx> + +#include <cutl/details/export.hxx> + +namespace cutl +{ + namespace compiler + { + class LIBCUTL_EXPORT context + { + public: + struct LIBCUTL_EXPORT no_entry: exception {}; + struct LIBCUTL_EXPORT typing: exception {}; + + public: + context () {} + + void + swap (context& c) + { + map_.swap (c.map_); + } + + private: + context (context const&); + + context& + operator= (context const&); + + public: + std::size_t + count (char const* key) const + { + return count (std::string (key)); + } + + std::size_t + count (std::string const& key) const + { + return map_.count (key); + } + + template <typename X> + X& + get (char const* key) + { + return get<X> (std::string (key)); + } + + template <typename X> + X& + get (std::string const& key); + + template <typename X> + X const& + get (char const* key) const + { + return get<X> (std::string (key)); + } + + template <typename X> + X const& + get (std::string const& key) const; + + template <typename X> + X const& + get (char const* key, X const& default_value) const + { + return get<X> (std::string (key), default_value); + } + + template <typename X> + X const& + get (std::string const& key, X const& default_value) const; + + template <typename X> + X& + set (char const* key, X const& value) + { + return set<X> (std::string (key), value); + } + + template <typename X> + X& + set (std::string const& key, X const& value); + + void + set (char const* key, container::any const& value) + { + return set (std::string (key), value); + } + + void + set (std::string const& key, container::any const& value); + + void + remove (char const* key) + { + remove (std::string (key)); + } + + void + remove (std::string const& key); + + std::type_info const& + type_info (char const* key) const + { + return type_info (std::string (key)); + } + + std::type_info const& + type_info (std::string const& key) const; + + private: + typedef std::map<std::string, container::any> map; + + map map_; + }; + } +} + +#include <cutl/compiler/context.txx> + +#endif // CUTL_COMPILER_CONTEXT_HXX diff --git a/libcutl/cutl/compiler/context.txx b/libcutl/cutl/compiler/context.txx new file mode 100644 index 0000000..53edcda --- /dev/null +++ b/libcutl/cutl/compiler/context.txx @@ -0,0 +1,88 @@ +// file : cutl/compiler/context.txx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + template <typename X> + X& context:: + get (std::string const& key) + { + map::iterator i (map_.find (key)); + + if (i == map_.end ()) + throw no_entry (); + + try + { + return i->second. template value<X> (); + } + catch (container::any::typing const&) + { + throw typing (); + } + } + + template <typename X> + X const& context:: + get (std::string const& key) const + { + map::const_iterator i (map_.find (key)); + + if (i == map_.end ()) + throw no_entry (); + + try + { + return i->second. template value<X> (); + } + catch (container::any::typing const&) + { + throw typing (); + } + } + + template <typename X> + X const& context:: + get (std::string const& key, X const& default_value) const + { + map::const_iterator i (map_.find (key)); + + if (i == map_.end ()) + return default_value; + + try + { + return i->second. template value<X> (); + } + catch (container::any::typing const&) + { + throw typing (); + } + } + + template <typename X> + X& context:: + set (std::string const& key, X const& value) + { + try + { + std::pair<map::iterator, bool> r ( + map_.insert (map::value_type (key, value))); + + X& x (r.first->second. template value<X> ()); + + if (!r.second) + x = value; + + return x; + } + catch (container::any::typing const&) + { + throw typing (); + } + } + } +} diff --git a/libcutl/cutl/compiler/cxx-indenter.cxx b/libcutl/cutl/compiler/cxx-indenter.cxx new file mode 100644 index 0000000..dba9f09 --- /dev/null +++ b/libcutl/cutl/compiler/cxx-indenter.cxx @@ -0,0 +1,49 @@ +// file : cutl/compiler/cxx-indenter.cxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include <cutl/compiler/cxx-indenter.hxx> + +namespace cutl +{ + namespace compiler + { + template<> + char const* cxx_indenter<char>:: + keyword (cxx_indenter<char>::keyword_type t) + { + static char const* keywords[] = + { + "if", + "do", + "for", + "else", + "case", + "while", + "catch", + "default" + }; + + return keywords[t]; + } + + template<> + wchar_t const* cxx_indenter<wchar_t>:: + keyword (cxx_indenter<wchar_t>::keyword_type t) + { + static wchar_t const* keywords[] = + { + L"if", + L"do", + L"for", + L"else", + L"case", + L"while", + L"catch", + L"default" + }; + + return keywords[t]; + } + } +} diff --git a/libcutl/cutl/compiler/cxx-indenter.hxx b/libcutl/cutl/compiler/cxx-indenter.hxx new file mode 100644 index 0000000..eac2952 --- /dev/null +++ b/libcutl/cutl/compiler/cxx-indenter.hxx @@ -0,0 +1,171 @@ +// file : cutl/compiler/cxx-indenter.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_CXX_INDENTER_HXX +#define CUTL_COMPILER_CXX_INDENTER_HXX + +#include <set> +#include <stack> +#include <deque> +#include <string> +#include <cstddef> // std::size_t + +#include <cutl/compiler/code-stream.hxx> + +namespace cutl +{ + namespace compiler + { + template <typename C> + class cxx_indenter: public code_stream<C> + { + public: + cxx_indenter (code_stream<C>& out); + + private: + cxx_indenter (cxx_indenter const&); + + cxx_indenter& + operator= (cxx_indenter const&); + + public: + virtual void + put (C); + + virtual void + unbuffer (); + + private: + typedef std::basic_string<C> string; + + enum construct + { + con_other, + con_pp_dir, + con_c_com, + con_cxx_com, + con_string_lit, + con_char_lit + }; + + private: + void + next_token (string const& old, C); + + void + ensure_new_line (); + + void + output_indentation (); + + void + write (C); + + private: + void + tokenize (C, construct old); + + void + retire (C); + + private: + enum char_class_type + { + cc_alpha, // Alpha + '_'. + cc_digit, + cc_op_punc, // Operator or punctuation. + cc_space + }; + + static char_class_type + char_class (C); + + private: + enum keyword_type + { + kw_if, + kw_do, + kw_for, + kw_else, + kw_case, + kw_while, + kw_catch, + kw_default + }; + + static C const* + keyword (keyword_type); + + private: + code_stream<C>& out_; + bool buffering_; // True if write() should buffer the char. + std::size_t position_; // Current position on the line. + std::size_t paren_balance_; // ( ) balance. + std::stack<std::size_t> indentation_; + std::size_t spaces_; + bool suppress_nl_; + construct construct_; + + // Special state stack for the do-while construct. The presence + // of an element in the stack indicates that we are in a braced + // do-while construct. The value of the element is the brace + // balance. + std::stack<std::size_t> do_while_state_; + + typedef std::deque<C> hold; + hold hold_; + + private: + string token_; // previously fully recognized token + string lexeme_; // current lexeme (accumulator) + + // Keywords that may be folowed by a single-line block, e.g., if, + // else, etc. + // + std::set<string> single_line_blocks_; + + // Keywords that may follow (and be related) to a previous block, + // e.g., else, case, catch. + // + std::set<string> follow_blocks_; + + string do_; + string lbrace_; + string rbrace_; + + private: + // Single-line indented blocks such as if, else, while, etc. The + // newline flag indicates whether a new line has been seen after + // the keyword. This is needed to properly distinguish cases such + // as: + // + // else if (...) + // foo (); + // + // else + // if (...) + // foo (); + // + struct indent_block + { + indent_block (bool newline, std::size_t indentation) + : newline_ (newline), indentation_ (indentation) + { + } + + bool newline_; + std::size_t indentation_; // Size of the indentation_ stack + // corresponding to this block, or + // 0 if it is not indented. + }; + + std::stack<indent_block> indent_stack_; + }; + } +} + +#include <cutl/compiler/cxx-indenter.ixx> +#include <cutl/compiler/cxx-indenter.txx> + +#endif // CUTL_COMPILER_CXX_INDENTER_HXX diff --git a/libcutl/cutl/compiler/cxx-indenter.ixx b/libcutl/cutl/compiler/cxx-indenter.ixx new file mode 100644 index 0000000..74bfac3 --- /dev/null +++ b/libcutl/cutl/compiler/cxx-indenter.ixx @@ -0,0 +1,69 @@ +// file : cutl/compiler/cxx-indenter.ixx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + template <typename C> + inline typename cxx_indenter<C>::char_class_type cxx_indenter<C>:: + char_class (C c) + { + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return cc_digit; + + case '!': + case '%': + case '^': + case '&': + case '*': + case '(': + case ')': + case '-': + case '+': + case '=': + case '{': + case '}': + case '|': + case '~': + case '[': + case ']': + case '\\': + case ';': + case '\'': + case ':': + case '"': + case '<': + case '>': + case '?': + case ',': + case '.': + case '/': + return cc_op_punc; + + case ' ': + case '\n': + case '\t': + case '\f': + case '\r': + case '\v': + return cc_space; + + default: + return cc_alpha; + } + } + } +} diff --git a/libcutl/cutl/compiler/cxx-indenter.txx b/libcutl/cutl/compiler/cxx-indenter.txx new file mode 100644 index 0000000..c3930b3 --- /dev/null +++ b/libcutl/cutl/compiler/cxx-indenter.txx @@ -0,0 +1,817 @@ +// file : cutl/compiler/cxx-indenter.txx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + template <typename C> + cxx_indenter<C>:: + cxx_indenter (code_stream<C>& out) + : out_ (out), + buffering_ (false), + position_ (0), + paren_balance_ (0), + spaces_ (2), + construct_ (con_other), + do_ (keyword(kw_do)), + lbrace_ (1, '{'), + rbrace_ (1, '}') + { + indentation_.push (0); + + single_line_blocks_.insert (keyword(kw_if)); + single_line_blocks_.insert (keyword(kw_do)); + single_line_blocks_.insert (keyword(kw_for)); + single_line_blocks_.insert (keyword(kw_else)); + single_line_blocks_.insert (keyword(kw_case)); + single_line_blocks_.insert (keyword(kw_while)); + + follow_blocks_.insert (keyword(kw_else)); + follow_blocks_.insert (keyword(kw_case)); + follow_blocks_.insert (keyword(kw_catch)); + follow_blocks_.insert (keyword(kw_default)); + } + + template <typename C> + void cxx_indenter<C>:: + put (C c) + { + // First determine what kind of construct we are in. + // + construct new_con (construct_); + construct old_con (construct_); + + switch (c) + { + case '\n': + { + if (construct_ == con_pp_dir || + construct_ == con_cxx_com) + construct_ = new_con = con_other; + + break; + } + case '#': + { + if (construct_ == con_other) + construct_ = new_con = con_pp_dir; + + break; + } + case '\"': + { + if (construct_ != con_pp_dir && + construct_ != con_c_com && + construct_ != con_cxx_com && + construct_ != con_char_lit) + { + // We might be in an escape sequence. + // + bool es (!hold_.empty () && hold_.back () == '\\'); + + if (es) + { + // Scan the hold sequence backwards to figure out if this + // backslash is part of this escape sequence or a preceding + // one. + // + for (typename hold::reverse_iterator i (hold_.rbegin () + 1), + e (hold_.rend ()); i != e && *i == '\\'; ++i) + es = !es; + } + + if (!es) + { + if (construct_ == con_string_lit) + new_con = con_other; + else + construct_ = new_con = con_string_lit; + } + } + + break; + } + case '\'': + { + if (construct_ != con_pp_dir && + construct_ != con_c_com && + construct_ != con_cxx_com && + construct_ != con_string_lit) + { + // We might be in an escape sequence. + // + bool es (!hold_.empty () && hold_.back () == '\\'); + + if (es) + { + // Scan the hold sequence backwards to figure out if this + // backslash is part of this escape sequence or a preceding + // one. + // + for (typename hold::reverse_iterator i (hold_.rbegin () + 1), + e (hold_.rend ()); i != e && *i == '\\'; ++i) + es = !es; + } + + if (!es) + { + if (construct_ == con_char_lit) + new_con = con_other; + else + construct_ = new_con = con_char_lit; + } + } + + break; + } + case '/': + { + if (construct_ == con_other) + { + if (!hold_.empty () && hold_.back () == '/') + construct_ = new_con = con_cxx_com; + } + + if (construct_ == con_c_com) + { + if (!hold_.empty () && hold_.back () == '*') + construct_ = new_con = con_other; + } + + break; + } + case '*': + { + if (construct_ == con_other) + { + if (!hold_.empty () && hold_.back () == '/') + construct_ = new_con = con_c_com; + } + + break; + } + default: + { + break; + } + } + + // Special handling of CPP directives. + // + if (construct_ == con_pp_dir) + { + write (c); + position_++; + return; + } + + // + // + tokenize (c, old_con); + + + // Indentation in parenthesis. We don't need to make sure + // we are not in a comments, etc., because we make sure we + // don't hold anything in those states. + // + if (!hold_.empty () && hold_.back () == '(') + { + unbuffer (); // We don't need to hold it anymore. + + if (c == '\n') + indentation_.push (indentation_.top () + spaces_); + else + indentation_.push (position_); + } + + + // + // + bool defaulting (false); + + switch (c) + { + case '\n': + { + if (!indent_stack_.empty () && construct_ == con_other) + indent_stack_.top ().newline_ = true; + + hold_.push_back (c); + position_ = 0; // Starting a new line. + + break; + } + case '{': + { + if (construct_ == con_other) + { + if (!indent_stack_.empty ()) + { + // Pop all the blocks until the one that was indented. + // + while (indent_stack_.top ().indentation_ == 0) + indent_stack_.pop (); + + // Pop the indented block and one level of indentation. + // + if (indentation_.size () > 1) + indentation_.pop (); + + indent_stack_.pop (); + } + + ensure_new_line (); + output_indentation (); + write (c); + ensure_new_line (); + + indentation_.push (indentation_.top () + spaces_); + } + else + defaulting = true; + + break; + } + case '}': + { + if (construct_ == con_other) + { + if (indentation_.size () > 1) + indentation_.pop (); + + // Reduce multiple newlines to one. + // + while (hold_.size () > 1) + { + typename hold::reverse_iterator i (hold_.rbegin ()); + + if (*i == '\n' && *(i + 1) == '\n') + hold_.pop_back (); + else + break; + } + + ensure_new_line (); + output_indentation (); + + hold_.push_back (c); + + // Add double newline after '}'. + // + hold_.push_back ('\n'); + hold_.push_back ('\n'); + position_ = 0; + + if (!indent_stack_.empty ()) + { + // Pop all the blocks until the one that was indented. + // + while (indent_stack_.top ().indentation_ == 0) + indent_stack_.pop (); + + // Now pop all the indented blocks while also popping the + // indentation stack. Do it only if the indentation match. + // If it doesn't then that means this inden_stack entry is + // for some other, outer block. + // + while (!indent_stack_.empty () && + indent_stack_.top ().indentation_ == + indentation_.size ()) + { + if (indentation_.size () > 1) + indentation_.pop (); + + indent_stack_.pop (); + } + } + + buffering_ = true; + } + else + defaulting = true; + + break; + } + case ';': + { + if (construct_ == con_other) + { + // for (;;) + // + if (!indent_stack_.empty () && paren_balance_ == 0) + { + // Pop all the blocks until the one that was indented. + // + while (indent_stack_.top ().indentation_ == 0) + indent_stack_.pop (); + + // Now pop all the indented blocks while also popping the + // indentation stack. Do it only if the indentation match. + // If they don't then it means we are inside a block and + // the stack should be popped after seeing '}', not ';'. + // + while (!indent_stack_.empty () && + indent_stack_.top ().indentation_ == + indentation_.size ()) + { + if (indentation_.size () > 1) + indentation_.pop (); + + indent_stack_.pop (); + } + } + + if (paren_balance_ != 0) + { + // We are inside for (;;) statement. Nothing to do here. + // + defaulting = true; + } + else + { + // Handling '};' case. + // + + bool brace (false); + + if (hold_.size () > 1 && hold_.back () == '\n') + { + bool pop_nl (false); + + for (typename hold::reverse_iterator + i (hold_.rbegin ()), e (hold_.rend ()); + i != e; ++i) + { + if (*i != '\n') + { + if (*i == '}') + brace = pop_nl = true; + + break; + } + } + + if (pop_nl) + while (hold_.back () == '\n') + hold_.pop_back (); + } + + output_indentation (); + write (c); + position_++; + + if (brace) + { + hold_.push_back ('\n'); + hold_.push_back ('\n'); + } + + ensure_new_line (); + } + } + else + defaulting = true; + + break; + } + case ',': + { + if (construct_ == con_other) + { + // Handling '},' case. + // + + bool brace (false); + + if (hold_.size () > 1 && hold_.back () == '\n') + { + bool pop_nl (false); + + for (typename hold::reverse_iterator + i (hold_.rbegin ()), e (hold_.rend ()); + i != e; ++i) + { + if (*i != '\n') + { + if (*i == '}') + brace = pop_nl = true; + + break; + } + } + + if (pop_nl) + while (hold_.back () == '\n') + hold_.pop_back (); + } + + output_indentation (); + write (c); + position_++; + + if (brace) + hold_.push_back ('\n'); + } + else + defaulting = true; + + break; + } + case ' ': + { + if (construct_ == con_other) + { + // Handling '} foo_;' case. + // + if (hold_.size () > 1 && hold_.back () == '\n') + { + bool pop_nl (false); + + for (typename hold::reverse_iterator + i (hold_.rbegin ()), e (hold_.rend ()); + i != e; ++i) + { + if (*i != '\n') + { + if (*i == '}') + pop_nl = true; + + break; + } + } + + if (pop_nl) + while (hold_.back () == '\n') + hold_.pop_back (); + } + } + + defaulting = true; + break; + } + case '\\': + { + if (construct_ != con_pp_dir && + construct_ != con_c_com && + construct_ != con_cxx_com) + { + output_indentation (); + hold_.push_back (c); + position_++; + } + else + defaulting = true; + + break; + + } + case '(': + { + if (construct_ == con_other) + { + // Hold it so that we can see what's coming next. + // + output_indentation (); + hold_.push_back (c); + position_++; + paren_balance_++; + } + else + defaulting = true; + break; + } + case ')': + { + if (construct_ == con_other) + { + if (indentation_.size () > 1) + indentation_.pop (); + + if (paren_balance_ > 0) + paren_balance_--; + } + + defaulting = true; + break; + } + case '/': + { + if (construct_ == con_other) + { + output_indentation (); + hold_.push_back (c); + position_++; + } + else + defaulting = true; + + break; + } + case '*': + { + if (construct_ == con_c_com) + { + output_indentation (); + hold_.push_back (c); + position_++; + } + else + defaulting = true; + + break; + } + default: + { + defaulting = true; + break; + } + } + + if (defaulting) + { + output_indentation (); + write (c); + position_++; + } + + construct_ = new_con; + } + + template <typename C> + void cxx_indenter<C>:: + unbuffer () + { + for (; !hold_.empty (); hold_.pop_front ()) + out_.put (hold_.front ()); + } + + template <typename C> + void cxx_indenter<C>:: + next_token (string const& old, C c) + { + // Handle one line indentation blocks (if, else, etc). + // + if (single_line_blocks_.find (token_) != single_line_blocks_.end ()) + { + // Only indent sub-blocks if we are on a new line. + // + bool indent (indent_stack_.empty () || + indent_stack_.top ().newline_); + + if (indent) + indentation_.push (indentation_.top () + spaces_); + + indent_stack_.push ( + indent_block (c == '\n', (indent ? indentation_.size () : 0))); + } + + // Keep track of the do ... while construct in order to suppress + // the newline after } and before while. + // + if (old == do_ && token_ == lbrace_) + do_while_state_.push (0); + + if (!do_while_state_.empty ()) + { + if (token_ == lbrace_) + do_while_state_.top ()++; + + if (token_ == rbrace_) + do_while_state_.top ()--; + } + + // Suppress double newline in the "}else", etc., cases. + // + if (old == rbrace_) + { + bool dw (!do_while_state_.empty () && do_while_state_.top () == 0); + + if (follow_blocks_.find (token_) != follow_blocks_.end () || dw) + { + if (dw) + do_while_state_.pop (); + + // Reduce double newline after "}" into a single one. + // + typename hold::iterator i (hold_.end ()), b (hold_.begin ()); + + for (--i; i != b; --i) + { + // See if this is the end of the "}\n\n" sequence. + // + if (*i == '\n') + { + --i; + if (i != b && *i == '\n') + { + --i; + if (*i == '}') + { + ++i; + hold_.erase (i); + break; + } + } + } + } + } + + // Stop buffering unless we have another closing brace. + // + if (token_ != rbrace_) + buffering_ = false; + } + } + + template <typename C> + void cxx_indenter<C>:: + ensure_new_line () + { + if (hold_.empty () || hold_.back () != '\n') + { + hold_.push_back ('\n'); + position_ = 0; // Starting a new line. + } + } + + + template <typename C> + void cxx_indenter<C>:: + output_indentation () + { + if (!hold_.empty () && hold_.back () == '\n') + { + for (std::size_t i (0); i < indentation_.top (); ++i) + write (' '); + + position_ += indentation_.top (); + } + } + + template <typename C> + void cxx_indenter<C>:: + write (C c) + { + hold_.push_back (c); + + if (!buffering_) + { + for (; !hold_.empty (); hold_.pop_front ()) + out_.put (hold_.front ()); + } + } + + template <typename C> + void cxx_indenter<C>:: + tokenize (C c, construct old) + { + // + // + switch (construct_) + { + case con_pp_dir: + { + if (old == con_other) // Start PP directive + retire (c); + + return; + } + case con_c_com: + { + if (old == con_other) // Start C comment. + lexeme_.clear (); + + return; + } + case con_cxx_com: + { + if (old == con_other) // Start C++ comment. + lexeme_.clear (); + + return; + } + case con_string_lit: + { + if (old == con_other) // Start string literal + retire (c); + + lexeme_ += c; + return; + } + case con_char_lit: + { + if (old == con_other) // Start char literal + retire (c); + + lexeme_ += c; + return; + } + default: + break; + } + + // construct_ == other + // + switch (old) + { + case con_pp_dir: + { + // End PP directive (newline). + // + return; + } + case con_c_com: + { + // End C comment. + // + return; + } + case con_cxx_com: + { + // End C++ comment (newline). + // + return; + } + case con_string_lit: + { + // End string literal ("). + // + lexeme_ += c; + return; + } + case con_char_lit: + { + // End char literal ('). + // + lexeme_ += c; + return; + } + default: + break; + } + + + // construct_ == old == other + // + + switch (char_class (c)) + { + case cc_alpha: + { + if (lexeme_.empty () || + char_class (lexeme_[0]) == cc_alpha) + lexeme_ += c; + else + { + retire (c); + lexeme_ += c; + } + break; + } + case cc_digit: + { + if (lexeme_.empty ()) + lexeme_ += c; + else + { + char_class_type cc (char_class (lexeme_[0])); + + if (cc == cc_alpha || cc == cc_digit) + lexeme_ += c; + else + { + retire (c); + lexeme_ += c; + } + } + break; + } + case cc_op_punc: + { + retire (c); + lexeme_ += c; + break; + } + case cc_space: + { + retire (c); + break; + } + } + } + + template <typename C> + void cxx_indenter<C>:: + retire (C c) + { + if (!lexeme_.empty ()) + { + token_.swap (lexeme_); + next_token (lexeme_, c); + lexeme_.clear (); + } + } + } +} diff --git a/libcutl/cutl/compiler/sloc-counter.hxx b/libcutl/cutl/compiler/sloc-counter.hxx new file mode 100644 index 0000000..cbcdede --- /dev/null +++ b/libcutl/cutl/compiler/sloc-counter.hxx @@ -0,0 +1,78 @@ +// file : cutl/compiler/sloc-counter.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_SLOC_COUNTER_HXX +#define CUTL_COMPILER_SLOC_COUNTER_HXX + +#include <cstddef> // std::size_t + +#include <cutl/compiler/code-stream.hxx> + +namespace cutl +{ + namespace compiler + { + template <typename C> + class sloc_counter: public code_stream<C> + { + public: + sloc_counter (code_stream<C>& out); + + std::size_t + count () const + { + return count_; + } + + private: + sloc_counter (sloc_counter const&); + + sloc_counter& + operator= (sloc_counter const&); + + public: + virtual void + put (C); + + virtual void + unbuffer (); + + private: + void + code (C); + + void + c_comment (C); + + void + cxx_comment (C); + + void + char_literal (C); + + void + string_literal (C); + + private: + code_stream<C>& out_; + std::size_t count_; + + C prev_; // Previous character or '\0'. + bool code_counted_; // This code line has already been counted. + + enum construct + { + con_code, + con_c_com, + con_cxx_com, + con_char_lit, + con_string_lit + } construct_; + }; + } +} + +#include <cutl/compiler/sloc-counter.txx> + +#endif // CUTL_COMPILER_SLOC_COUNTER_HXX diff --git a/libcutl/cutl/compiler/sloc-counter.txx b/libcutl/cutl/compiler/sloc-counter.txx new file mode 100644 index 0000000..3b741ad --- /dev/null +++ b/libcutl/cutl/compiler/sloc-counter.txx @@ -0,0 +1,224 @@ +// file : cutl/compiler/sloc-counter.txx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include <cctype> // std::isspace + +namespace cutl +{ + namespace compiler + { + template <typename C> + sloc_counter<C>:: + sloc_counter (code_stream<C>& out) + : out_ (out), + count_ (0), + prev_ ('\0'), + code_counted_ (false), + construct_ (con_code) + { + } + + template <typename C> + void sloc_counter<C>:: + put (C c) + { + construct old (construct_); + + switch (construct_) + { + case con_code: + { + code (c); + break; + } + case con_c_com: + { + c_comment (c); + break; + } + case con_cxx_com: + { + cxx_comment (c); + break; + } + case con_char_lit: + { + char_literal (c); + break; + } + case con_string_lit: + { + string_literal (c); + break; + } + } + + // There are cases when a previous character has been already + // 'used' and therefore can not be used again. Good example + // would be '/* *//'. Here, the second slash doesn't start + // C++ comment since it was already used by C comment. + // + // To account for this we are going to set prev_ to '\0' when + // the mode changes. + // + + prev_ = (old == construct_) ? c : '\0'; + + out_.put (c); + } + + template <typename C> + void sloc_counter<C>:: + unbuffer () + { + } + + template <typename C> + void sloc_counter<C>:: + code (C c) + { + bool count (true); + + switch (c) + { + case '/': + { + if (prev_ == '/') + { + construct_ = con_cxx_com; + count = false; + } + else + { + // This slash can be a beginning of a comment but we + // yet have no way to know. Will have to examine it later + // (see below). + // + count = false; + } + + break; + } + case '*': + { + if (prev_ == '/') + { + construct_ = con_c_com; + count = false; + } + break; + } + case '\'': + { + construct_ = con_char_lit; + break; + } + case '"': + { + construct_ = con_string_lit; + break; + } + case '\n': + { + code_counted_ = false; // Reset for a new line. + count = false; + break; + } + default: + { + if (std::isspace (c)) + count = false; + break; + } + } + + if (!code_counted_) + { + if (count) + { + count_++; + code_counted_ = true; + } + else if (prev_ == '/' && construct_ == con_code) + { + // This condition accounts for the fact that we cannot count + // '/' right away since it can be a beginning of a comment. + // + count_++; + code_counted_ = (c != '\n'); + } + } + } + + template <typename C> + void sloc_counter<C>:: + c_comment (C c) + { + switch (c) + { + case '/': + { + if (prev_ == '*') + construct_ = con_code; + break; + } + case '\n': + { + code_counted_ = false; // Reset for a new line. + break; + } + } + } + + template <typename C> + void sloc_counter<C>:: + cxx_comment (C c) + { + switch (c) + { + case '\n': + { + construct_ = con_code; + code_counted_ = false; // Reset for a new line. + break; + } + } + } + + template <typename C> + void sloc_counter<C>:: + char_literal (C c) + { + switch (c) + { + case '\'': + { + if (prev_ != '\\') + construct_ = con_code; + break; + } + } + } + + template <typename C> + void sloc_counter<C>:: + string_literal (C c) + { + switch (c) + { + case '"': + { + if (prev_ != '\\') + construct_ = con_code; + break; + } + case '\n': + { + count_++; + break; + } + } + } + } +} diff --git a/libcutl/cutl/compiler/traversal.hxx b/libcutl/cutl/compiler/traversal.hxx new file mode 100644 index 0000000..e0b6d77 --- /dev/null +++ b/libcutl/cutl/compiler/traversal.hxx @@ -0,0 +1,171 @@ +// file : cutl/compiler/traversal.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_TRAVERSAL_HXX +#define CUTL_COMPILER_TRAVERSAL_HXX + +#include <map> +#include <set> +#include <vector> + +#include <cutl/compiler/type-info.hxx> + +namespace cutl +{ + namespace compiler + { + // + // + template<typename B> + class traverser + { + public: + virtual + ~traverser (); + + virtual void + trampoline (B&) = 0; + }; + + // + // + template<typename B> + class traverser_map + { + public: + typedef std::vector<traverser<B>*> traversers; + + struct map_type: std::map<type_id, traversers> + { + map_type () {} + + // Don't copy traverser maps. We do it here instead of in + // traverser_map to pacify GCC's -Wextra insisting we must + // explicitly initialize virtual bases in copy constructor. + // + map_type (map_type const&): std::map<type_id, traversers> () {} + map_type& operator= (map_type const&) {return *this;} + }; + + typedef typename map_type::const_iterator iterator; + + iterator + begin () const + { + return map_.begin (); + } + + iterator + end () const + { + return map_.end (); + } + + void + add (type_id const& id, traverser<B>& t) + { + traversers& travs (map_[id]); + travs.push_back (&t); + } + + protected: + map_type map_; + }; + + // + // + template <typename X, typename B> + class traverser_impl: public traverser<B>, + public virtual traverser_map<B> + { + public: + typedef X type; + + traverser_impl () + { + this->add (typeid (type), *this); + } + + traverser_impl (traverser_impl const&) + { + this->add (typeid (type), *this); + } + + virtual void + traverse (type&) = 0; + + public: + virtual void + trampoline (B&); + }; + + // + // + template <typename B> + class dispatcher: public virtual traverser_map<B> + { + public: + virtual + ~dispatcher (); + + void + traverser (traverser_map<B>&); + + virtual void + dispatch (B&); + + public: + template <typename I, typename X> + static void + iterate_and_dispatch (I begin, I end, dispatcher<X>& d) + { + for (; begin != end; ++begin) + { + d.dispatch (*begin); + } + } + + template <typename T, typename A, typename I, typename X> + static void + iterate_and_dispatch (I begin, + I end, + dispatcher<X>& d, + T& t, + void (T::*next)(A&), + A& a) + { + for (; begin != end;) + { + d.dispatch (*begin); + + if (++begin != end && next != 0) + (t.*next) (a); + } + } + + private: + struct comparator + { + bool + operator () (type_info const& a, type_info const& b) const + { + return a.type_id () < b.type_id (); + } + }; + + typedef std::map<type_info, std::size_t, comparator> level_map; + typedef std::set<type_info, comparator> type_info_set; + + static std::size_t + compute_levels (type_info const&, std::size_t current, level_map&); + + static void + flatten_tree (type_info const&, type_info_set&); + }; + } +} + +#include <cutl/compiler/traversal.txx> + +#endif // CUTL_COMPILER_TRAVERSAL_HXX diff --git a/libcutl/cutl/compiler/traversal.txx b/libcutl/cutl/compiler/traversal.txx new file mode 100644 index 0000000..21200bc --- /dev/null +++ b/libcutl/cutl/compiler/traversal.txx @@ -0,0 +1,144 @@ +// file : cutl/compiler/traversal.txx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + // traverser + // + template<typename B> + traverser<B>:: + ~traverser () + { + } + + // traverser_impl + // + + template <typename X, typename B> + void traverser_impl<X, B>:: + trampoline (B& x) + { + this->traverse (dynamic_cast<type&> (x)); + } + + // dispatcher + // + + template <typename B> + dispatcher<B>:: + ~dispatcher () + { + } + + template <typename B> + void dispatcher<B>:: + traverser (traverser_map<B>& m) + { + // Copy entries from m to our map. + // + for (typename traverser_map<B>::iterator + i (m.begin ()), e (m.end ()); i != e; ++i) + { + typename traverser_map<B>::traversers& travs (this->map_[i->first]); + + for (typename traverser_map<B>::traversers::const_iterator + t (i->second.begin ()), e (i->second.end ()); t != e; ++t) + { + travs.push_back (*t); + } + } + } + + template <typename B> + void dispatcher<B>:: + dispatch (B& x) + { + using std::size_t; + + level_map levels; + type_info const& ti (lookup (x)); + size_t max (compute_levels (ti, 0, levels)); + + // cerr << "starting dispatch process for " << ti.type_id ().name () + // << " with " << max << " levels" << endl; + + for (size_t l (0); l < max + 1; ++l) + { + type_info_set dispatched; + + for (typename level_map::const_iterator + i (levels.begin ()), e (levels.end ()); i != e; ++i) + { + if (i->second == l) + { + typename traverser_map<B>::map_type::const_iterator v ( + this->map_.find (i->first.type_id ())); + + if (v != this->map_.end ()) + { + // cerr << "dispatching traversers for " << ti.type_id ().name () + // << " as " << i->first.type_id ().name () << endl; + + typename traverser_map<B>::traversers const& travs (v->second); + + for (typename traverser_map<B>::traversers::const_iterator + ti (travs.begin ()), te (travs.end ()); ti != te; ++ti) + { + (*ti)->trampoline (x); + } + + flatten_tree (i->first, dispatched); + } + } + } + + // Remove traversed types from the level map. + // + for (typename type_info_set::const_iterator i (dispatched.begin ()); + i != dispatched.end (); ++i) + { + levels.erase (*i); + } + } + } + + template <typename B> + std::size_t dispatcher<B>:: + compute_levels (type_info const& ti, std::size_t cur, level_map& map) + { + using std::size_t; + + size_t ret (cur); + + if (map.find (ti) == map.end () || map[ti] < cur) + map[ti] = cur; + + for (type_info::base_iterator i (ti.begin_base ()); + i != ti.end_base (); ++i) + { + size_t tmp (compute_levels (i->type_info (), cur + 1, map)); + + if (tmp > ret) + ret = tmp; + } + + return ret; + } + + template <typename B> + void dispatcher<B>:: + flatten_tree (type_info const& ti, type_info_set& set) + { + set.insert (ti); + + for (type_info::base_iterator i (ti.begin_base ()); + i != ti.end_base (); ++i) + { + flatten_tree (i->type_info (), set); + } + } + } +} diff --git a/libcutl/cutl/compiler/type-id.hxx b/libcutl/cutl/compiler/type-id.hxx new file mode 100644 index 0000000..f37454e --- /dev/null +++ b/libcutl/cutl/compiler/type-id.hxx @@ -0,0 +1,48 @@ +// file : cutl/compiler/type-id.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_TYPE_ID_HXX +#define CUTL_COMPILER_TYPE_ID_HXX + +#include <typeinfo> // std::type_info + +#include <cutl/details/export.hxx> + +namespace cutl +{ + namespace compiler + { + class LIBCUTL_EXPORT type_id + { + public: + template<typename X> + type_id (X const volatile&); + + type_id (std::type_info const&); + + public: + char const* + name () const; + + friend bool + operator== (type_id const&, type_id const&); + + friend bool + operator!= (type_id const&, type_id const&); + + friend bool + operator< (type_id const&, type_id const&); + + private: + std::type_info const* ti_; + }; + + typedef type_id type_id_t; + } +} + +#include <cutl/compiler/type-id.ixx> +#include <cutl/compiler/type-id.txx> + +#endif // CUTL_COMPILER_TYPE_ID_HXX diff --git a/libcutl/cutl/compiler/type-id.ixx b/libcutl/cutl/compiler/type-id.ixx new file mode 100644 index 0000000..2e9f963 --- /dev/null +++ b/libcutl/cutl/compiler/type-id.ixx @@ -0,0 +1,44 @@ +// file : cutl/compiler/type-id.ixx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + inline + type_id:: + type_id (std::type_info const& ti) + : ti_ (&ti) + { + } + + inline + char const* type_id:: + name () const + { + return ti_->name (); + } + + inline + bool + operator== (type_id const& x, type_id const& y) + { + return *x.ti_ == *y.ti_; + } + + inline + bool + operator!= (type_id const& x, type_id const& y) + { + return *x.ti_ != *y.ti_; + } + + inline + bool + operator< (type_id const& x, type_id const& y) + { + return x.ti_->before (*y.ti_); + } + } +} diff --git a/libcutl/cutl/compiler/type-id.txx b/libcutl/cutl/compiler/type-id.txx new file mode 100644 index 0000000..bc7a2e3 --- /dev/null +++ b/libcutl/cutl/compiler/type-id.txx @@ -0,0 +1,17 @@ +// file : cutl/compiler/type-id.txx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + template <typename X> + inline + type_id:: + type_id (X const volatile& x) + : ti_ (&typeid (x)) + { + } + } +} diff --git a/libcutl/cutl/compiler/type-info.cxx b/libcutl/cutl/compiler/type-info.cxx new file mode 100644 index 0000000..b4353b3 --- /dev/null +++ b/libcutl/cutl/compiler/type-info.cxx @@ -0,0 +1,30 @@ +// file : cutl/compiler/type-info.cxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include <cutl/compiler/type-info.hxx> + +namespace cutl +{ + namespace compiler + { + using namespace bits; + + type_info const& + lookup (type_id const& tid) + { + type_info_map::const_iterator i (type_info_map_->find (tid)); + + if (i == type_info_map_->end ()) + throw no_type_info (); + + return i->second; + } + + void + insert (type_info const& ti) + { + type_info_map_->insert (type_info_map::value_type (ti.type_id (), ti)); + } + } +} diff --git a/libcutl/cutl/compiler/type-info.hxx b/libcutl/cutl/compiler/type-info.hxx new file mode 100644 index 0000000..8d9a32b --- /dev/null +++ b/libcutl/cutl/compiler/type-info.hxx @@ -0,0 +1,111 @@ +// file : cutl/compiler/type-info.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CUTL_COMPILER_TYPE_INFO_HXX +#define CUTL_COMPILER_TYPE_INFO_HXX + +#include <map> +#include <vector> +#include <typeinfo> // std::type_info + +#include <cutl/exception.hxx> +#include <cutl/static-ptr.hxx> +#include <cutl/compiler/type-id.hxx> + +#include <cutl/details/export.hxx> + +namespace cutl +{ + namespace compiler + { + // + // + class type_info; + typedef type_info type_info_t; + + + // + // + class LIBCUTL_EXPORT base_info + { + public: + base_info (type_id const&); + + public: + type_info_t const& + type_info () const; + + private: + type_id type_id_; + mutable type_info_t const* type_info_; + }; + + typedef base_info base_info_t; + + + // + // + class LIBCUTL_EXPORT type_info + { + typedef std::vector<base_info> bases; + + public: + typedef + bases::const_iterator + base_iterator; + + public: + type_info (type_id_t const&); + + type_id_t + type_id () const; + + base_iterator + begin_base () const; + + base_iterator + end_base () const; + + void + add_base (type_id_t const&); + + private: + type_id_t type_id_; + bases bases_; + }; + + + // + // + class LIBCUTL_EXPORT no_type_info: exception {}; + + LIBCUTL_EXPORT type_info const& + lookup (type_id const&); + + LIBCUTL_EXPORT type_info const& + lookup (std::type_info const&); + + template <typename X> + type_info const& + lookup (X const volatile&); + + template<typename X> + type_info const& + lookup (); + + LIBCUTL_EXPORT void + insert (type_info const&); + + namespace bits + { + struct default_type_info_id {}; + typedef std::map<type_id, type_info> type_info_map; + static static_ptr<type_info_map, default_type_info_id> type_info_map_; + } + } +} + +#include <cutl/compiler/type-info.ixx> + +#endif // CUTL_COMPILER_TYPE_INFO_HXX diff --git a/libcutl/cutl/compiler/type-info.ixx b/libcutl/cutl/compiler/type-info.ixx new file mode 100644 index 0000000..bf0987c --- /dev/null +++ b/libcutl/cutl/compiler/type-info.ixx @@ -0,0 +1,95 @@ +// file : cutl/compiler/type-info.ixx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +namespace cutl +{ + namespace compiler + { + // base_info + // + + inline + base_info:: + base_info (type_id const& type_id) + : type_id_ (type_id), type_info_ (0) + { + } + + inline + type_info_t const& base_info:: + type_info () const + { + // We need to do delayed lookup because of the unpredictable + // order in which type information may be added. + // + // @@ MT-unsafe + // + if (type_info_ == 0) + type_info_ = &(lookup (type_id_)); + + return *type_info_; + } + + // type_info + // + + inline + type_info:: + type_info (type_id_t const& tid) + : type_id_ (tid) + { + } + + inline + type_id_t type_info:: + type_id () const + { + return type_id_; + } + + inline + type_info::base_iterator type_info:: + begin_base () const + { + return bases_.begin (); + } + + + inline + type_info::base_iterator type_info:: + end_base () const + { + return bases_.end (); + } + + inline + void type_info:: + add_base (type_id_t const& tid) + { + bases_.push_back (base_info (tid)); + } + + // + // + inline type_info const& + lookup (std::type_info const& tid) + { + return lookup (type_id (tid)); + } + + template <typename X> + inline type_info const& + lookup (X const volatile& x) + { + return lookup (typeid (x)); + } + + template<typename X> + inline type_info const& + lookup () + { + return lookup (typeid (X)); + } + } +} |