summaryrefslogtreecommitdiff
path: root/libbackend-elements/backend-elements
diff options
context:
space:
mode:
Diffstat (limited to 'libbackend-elements/backend-elements')
-rw-r--r--libbackend-elements/backend-elements/indentation/buffer.hxx61
-rw-r--r--libbackend-elements/backend-elements/indentation/buffer.txx12
-rw-r--r--libbackend-elements/backend-elements/indentation/clip.hxx173
-rw-r--r--libbackend-elements/backend-elements/indentation/clip.txx12
-rw-r--r--libbackend-elements/backend-elements/indentation/cxx.hxx1016
-rw-r--r--libbackend-elements/backend-elements/indentation/cxx.txx12
-rw-r--r--libbackend-elements/backend-elements/indentation/idl.hxx290
-rw-r--r--libbackend-elements/backend-elements/indentation/idl.txx11
-rw-r--r--libbackend-elements/backend-elements/indentation/sloc.hxx277
-rw-r--r--libbackend-elements/backend-elements/makefile63
-rw-r--r--libbackend-elements/backend-elements/regex.hxx208
-rw-r--r--libbackend-elements/backend-elements/regex.txx52
-rw-r--r--libbackend-elements/backend-elements/types.hxx16
13 files changed, 2203 insertions, 0 deletions
diff --git a/libbackend-elements/backend-elements/indentation/buffer.hxx b/libbackend-elements/backend-elements/indentation/buffer.hxx
new file mode 100644
index 0000000..7058814
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/buffer.hxx
@@ -0,0 +1,61 @@
+// file : backend-elements/indentation/buffer.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_INDENTATION_BUFFER_HXX
+#define BACKEND_ELEMENTS_INDENTATION_BUFFER_HXX
+
+#include <backend-elements/types.hxx>
+
+#include <string>
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ template <typename C>
+ class Buffer: public NonCopyable
+ {
+ public:
+ struct Write {};
+
+ public:
+ virtual
+ ~Buffer ()
+ {
+ }
+
+ public:
+ typedef
+ std::char_traits<C>
+ Traits;
+
+ typedef
+ typename Traits::char_type
+ AsChar;
+
+ typedef
+ typename Traits::int_type
+ AsInt;
+
+ public:
+ virtual AsInt
+ put (AsChar 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;
+ };
+ }
+}
+
+#include <backend-elements/indentation/buffer.txx>
+
+#endif // BACKEND_ELEMENTS_INDENTATION_BUFFER_HXX
diff --git a/libbackend-elements/backend-elements/indentation/buffer.txx b/libbackend-elements/backend-elements/indentation/buffer.txx
new file mode 100644
index 0000000..57ba7ab
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/buffer.txx
@@ -0,0 +1,12 @@
+// file : backend-elements/indentation/buffer.txx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ }
+}
+
diff --git a/libbackend-elements/backend-elements/indentation/clip.hxx b/libbackend-elements/backend-elements/indentation/clip.hxx
new file mode 100644
index 0000000..068ed0d
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/clip.hxx
@@ -0,0 +1,173 @@
+// file : backend-elements/indentation/clip.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_INDENTATION_CLIP_HXX
+#define BACKEND_ELEMENTS_INDENTATION_CLIP_HXX
+
+#include <backend-elements/types.hxx>
+
+#include <backend-elements/indentation/buffer.hxx>
+
+#include <ostream>
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ template <typename C>
+ class ToStreambufAdapter: public std::basic_streambuf<C>,
+ public NonCopyable
+ {
+ public:
+ typedef
+ typename std::basic_streambuf<C>::traits_type
+ Traits;
+
+ typedef
+ typename std::basic_streambuf<C>::char_type
+ AsChar;
+
+ typedef
+ typename std::basic_streambuf<C>::int_type
+ AsInt;
+
+ public:
+ ToStreambufAdapter (Buffer<C>& buffer)
+ : buffer_ (buffer)
+ {
+ }
+
+ virtual AsInt
+ overflow (AsInt ch)
+ {
+ return buffer_.put (Traits::to_char_type (ch));
+ }
+
+ virtual Int
+ sync ()
+ {
+ return 0;
+ }
+
+ private:
+ Buffer<C>& buffer_;
+ };
+
+
+ template <typename C>
+ class FromStreambufAdapter: public Buffer<C>
+ {
+ public:
+ typedef
+ typename Buffer<C>::Traits
+ Traits;
+
+ typedef
+ typename Buffer<C>::AsChar
+ AsChar;
+
+ typedef
+ typename Buffer<C>::AsInt
+ AsInt;
+
+ typedef
+ typename Buffer<C>::Write
+ Write;
+
+ public:
+ FromStreambufAdapter (std::basic_streambuf<C>& b)
+ : buffer_ (b)
+ {
+ }
+
+ virtual AsInt
+ put (AsChar ch)
+ {
+ return buffer_.sputc (ch);
+ }
+
+ virtual Void
+ unbuffer ()
+ {
+ try
+ {
+ if (buffer_.pubsync () == 0) return;
+ }
+ catch (std::ios_base::failure const&)
+ {
+ }
+
+ throw Write ();
+ }
+
+ private:
+ std::basic_streambuf<C>& buffer_;
+ };
+
+
+ template <template <typename> class Buffer, typename C = Char>
+ class Clip: public NonCopyable
+ {
+ public:
+ Clip (std::basic_ostream<C>& os)
+ : os_ (os),
+ prev_ (os_.rdbuf ()),
+ from_adapter_ (*prev_),
+ buffer_ (from_adapter_),
+ to_adapter_ (buffer_)
+ {
+ os_.rdbuf (&to_adapter_);
+ }
+
+ /*
+ template <typename Arg0>
+ Clip (std::basic_ostream<C>& os, Arg0 a0)
+ : os_ (os),
+ prev_ (os_.rdbuf ()),
+ from_adapter_ (*prev_),
+ buffer_ (from_adapter_, a0),
+ to_adapter_ (buffer_)
+ {
+ os_.rdbuf (&to_adapter_);
+ }
+ */
+
+ ~Clip ()
+ {
+ try
+ {
+ buffer_.unbuffer ();
+ }
+ catch (...)
+ {
+ os_.rdbuf (prev_);
+ throw;
+ }
+
+ os_.rdbuf (prev_);
+ }
+
+ Buffer<C>&
+ buffer ()
+ {
+ return buffer_;
+ }
+
+ private:
+ std::basic_ostream<C>& os_;
+ std::basic_streambuf<C>* prev_;
+
+ FromStreambufAdapter<C> from_adapter_;
+
+ Buffer<C> buffer_;
+
+ ToStreambufAdapter<C> to_adapter_;
+ };
+ }
+}
+
+#include <backend-elements/indentation/clip.txx>
+
+#endif // BACKEND_ELEMENTS_INDENTATION_CLIP_HXX
diff --git a/libbackend-elements/backend-elements/indentation/clip.txx b/libbackend-elements/backend-elements/indentation/clip.txx
new file mode 100644
index 0000000..58112f1
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/clip.txx
@@ -0,0 +1,12 @@
+// file : backend-elements/indentation/clip.txx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ }
+}
+
diff --git a/libbackend-elements/backend-elements/indentation/cxx.hxx b/libbackend-elements/backend-elements/indentation/cxx.hxx
new file mode 100644
index 0000000..f10341a
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/cxx.hxx
@@ -0,0 +1,1016 @@
+// file : backend-elements/indentation/cxx.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_INDENTATION_CXX_HXX
+#define BACKEND_ELEMENTS_INDENTATION_CXX_HXX
+
+#include <backend-elements/types.hxx>
+#include <backend-elements/indentation/buffer.hxx>
+
+#include <cult/containers/set.hxx>
+#include <cult/containers/stack.hxx>
+#include <cult/containers/deque.hxx>
+
+#include <locale>
+
+// #include <iostream> // @@ tmp
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ template <typename C>
+ class CXX: public Buffer<C>/*, public NonCopyable*/
+ {
+ public:
+ typedef
+ typename Buffer<C>::Traits
+ Traits;
+
+ typedef
+ typename Buffer<C>::AsChar
+ AsChar;
+
+ typedef
+ typename Buffer<C>::AsInt
+ AsInt;
+
+ typedef
+ typename Buffer<C>::Write
+ Write;
+
+ public:
+ CXX (Buffer<C>& out)
+ : out_ (out),
+ buffering_ (false),
+ position_ (0),
+ paren_balance_ (0),
+ spaces_ (2),
+ construct_ (Construct::other),
+ lbrace_ ("{"),
+ rbrace_ ("}")
+ // locale_ ("C")
+ {
+ indentation_.push (0);
+
+ single_line_blocks_.insert ("if");
+ single_line_blocks_.insert ("do");
+ single_line_blocks_.insert ("for");
+ single_line_blocks_.insert ("else");
+ single_line_blocks_.insert ("case");
+ single_line_blocks_.insert ("while");
+
+ follow_blocks_.insert ("else");
+ follow_blocks_.insert ("case");
+ follow_blocks_.insert ("catch");
+ follow_blocks_.insert ("default");
+ }
+
+ public:
+ virtual AsInt
+ put (AsChar c)
+ {
+ AsInt result (Traits::to_int_type (c));
+
+ try
+ {
+ // First determine what kind of construct we are in.
+ //
+ typename Construct::Value new_construct (construct_);
+ typename Construct::Value old_construct (construct_);
+
+ switch (c)
+ {
+ case '\n':
+ {
+ if (construct_ == Construct::pp_directive ||
+ construct_ == Construct::cxx_comment)
+ construct_ = new_construct = Construct::other;
+
+ break;
+ }
+ case '#':
+ {
+ if (construct_ == Construct::other)
+ construct_ = new_construct = Construct::pp_directive;
+
+ break;
+ }
+ case '\"':
+ {
+ if (construct_ != Construct::pp_directive &&
+ construct_ != Construct::c_comment &&
+ construct_ != Construct::cxx_comment &&
+ construct_ != Construct::char_literal)
+ {
+ // We might be in an escape sequence.
+ //
+ Boolean 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::ReverseIterator i (hold_.rbegin () + 1),
+ e (hold_.rend ()); i != e && *i == '\\'; ++i)
+ es = !es;
+ }
+
+ if (!es)
+ {
+ // Not an escape sequence.
+ //
+ if (construct_ == Construct::string_literal)
+ new_construct = Construct::other;
+ else
+ construct_ = new_construct = Construct::string_literal;
+ }
+ }
+
+ break;
+ }
+ case '\'':
+ {
+ if (construct_ != Construct::pp_directive &&
+ construct_ != Construct::c_comment &&
+ construct_ != Construct::cxx_comment &&
+ construct_ != Construct::string_literal)
+ {
+ // We might be in an escape sequence.
+ //
+ Boolean 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::ReverseIterator i (hold_.rbegin () + 1),
+ e (hold_.rend ()); i != e && *i == '\\'; ++i)
+ es = !es;
+ }
+
+ if (!es)
+ {
+ if (construct_ == Construct::char_literal)
+ new_construct = Construct::other;
+ else
+ construct_ = new_construct = Construct::char_literal;
+ }
+ }
+
+ break;
+ }
+ case '/':
+ {
+ if (construct_ == Construct::other)
+ {
+ if (!hold_.empty () && hold_.back () == '/')
+ construct_ = new_construct = Construct::cxx_comment;
+ }
+
+ if (construct_ == Construct::c_comment)
+ {
+ if (!hold_.empty () && hold_.back () == '*')
+ construct_ = new_construct = Construct::other;
+ }
+
+ break;
+ }
+ case '*':
+ {
+ if (construct_ == Construct::other)
+ {
+ if (!hold_.empty () && hold_.back () == '/')
+ construct_ = new_construct = Construct::c_comment;
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ // Special handling of CPP directives.
+ //
+ if (construct_ == Construct::pp_directive)
+ {
+ result = write (c);
+ position_++;
+ return result;
+ }
+
+ //
+ //
+ tokenize (c, old_construct);
+
+
+ // 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_);
+ }
+
+
+ //
+ //
+ Boolean defaulting (false);
+
+ switch (c)
+ {
+ case '\n':
+ {
+ if (!indent_block_.empty () && construct_ == Construct::other)
+ indent_block_.top ().newline_ = true;
+
+ hold_.push_back (c);
+ position_ = 0; // Starting a new line.
+
+ break;
+ }
+ case '{':
+ {
+ if (construct_ == Construct::other)
+ {
+ if (!indent_block_.empty ())
+ {
+ // Pop all the blocks until the one that was indented.
+ //
+ while (!indent_block_.top ().indented_)
+ indent_block_.pop ();
+
+ if (indentation_.size () > 1)
+ indentation_.pop ();
+
+ indent_block_.pop ();
+ }
+
+ ensure_new_line ();
+ output_indentation ();
+ result = write (c);
+ ensure_new_line ();
+
+ indentation_.push (indentation_.top () + spaces_);
+ }
+ else
+ defaulting = true;
+
+ break;
+ }
+ case '}':
+ {
+ if (construct_ == Construct::other)
+ {
+ if (indentation_.size () > 1)
+ indentation_.pop ();
+
+ // Reduce multiple newlines to one.
+ //
+ while (hold_.size () > 1)
+ {
+ typename Hold::ReverseIterator 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;
+
+ buffering_ = true;
+ }
+ else
+ defaulting = true;
+
+ break;
+ }
+ case ';':
+ {
+ if (construct_ == Construct::other)
+ {
+ // for (;;)
+ //
+ if (!indent_block_.empty () && paren_balance_ == 0)
+ {
+ // Pop all the blocks until the one that was indented.
+ //
+ while (!indent_block_.top ().indented_)
+ indent_block_.pop ();
+
+ if (indentation_.size () > 1)
+ indentation_.pop ();
+
+ indent_block_.pop ();
+ }
+
+ if (paren_balance_ != 0)
+ {
+ // We are inside for (;;) statement. Nothing to do here.
+ //
+ defaulting = true;
+ }
+ else
+ {
+ // Handling '};' case.
+ //
+
+ Boolean brace (false);
+
+ if (hold_.size () > 1 && hold_.back () == '\n')
+ {
+ Boolean pop_nl (false);
+
+ for (typename Hold::ReverseIterator
+ 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 ();
+ result = write (c);
+ position_++;
+
+ if (brace)
+ {
+ hold_.push_back ('\n');
+ hold_.push_back ('\n');
+ }
+
+ ensure_new_line ();
+ }
+ }
+ else
+ defaulting = true;
+
+ break;
+ }
+ case ' ':
+ {
+ if (construct_ == Construct::other)
+ {
+ // Handling '} foo_;' case.
+ //
+ if (hold_.size () > 1 && hold_.back () == '\n')
+ {
+ Boolean pop_nl (false);
+
+ for (typename Hold::ReverseIterator
+ 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_ != Construct::pp_directive &&
+ construct_ != Construct::c_comment &&
+ construct_ != Construct::cxx_comment)
+ {
+ output_indentation ();
+ hold_.push_back (c);
+ position_++;
+ }
+ else
+ defaulting = true;
+
+ break;
+
+ }
+ case '(':
+ {
+ if (construct_ == Construct::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_ == Construct::other)
+ {
+ if (indentation_.size () > 1)
+ indentation_.pop ();
+
+ if (paren_balance_ > 0)
+ paren_balance_--;
+ }
+
+ defaulting = true;
+ break;
+ }
+ case '/':
+ {
+ if (construct_ == Construct::other)
+ {
+ output_indentation ();
+ hold_.push_back (c);
+ position_++;
+ }
+ else
+ defaulting = true;
+
+ break;
+ }
+ case '*':
+ {
+ if (construct_ == Construct::c_comment)
+ {
+ output_indentation ();
+ hold_.push_back (c);
+ position_++;
+ }
+ else
+ defaulting = true;
+
+ break;
+ }
+ default:
+ {
+ defaulting = true;
+ break;
+ }
+ }
+
+
+ if (defaulting)
+ {
+ output_indentation ();
+ result = write (c);
+ position_++;
+ }
+
+ construct_ = new_construct;
+ }
+ catch (Write const&)
+ {
+ result = Traits::eof ();
+ }
+
+ return result;
+ }
+
+ private:
+ typedef Cult::StringTemplate<C> String;
+
+ Void
+ next_token (String const& old, AsChar c)
+ {
+ //std::cerr << "next token: " << token_
+ // << "; old token: " << old << std::endl;
+
+ // 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.
+ //
+ Boolean indent (indent_block_.empty () ||
+ indent_block_.top ().newline_);
+
+ indent_block_.push (IndentBlockInfo (c == '\n', indent));
+
+ if (indent)
+ indentation_.push (indentation_.top () + spaces_);
+ }
+
+ // Keep track of the do ... while construct in order to suppress
+ // the newline after } and before while.
+ //
+ if (old == String ("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_)
+ {
+ Boolean 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;
+ }
+ }
+ }
+ }
+ }
+ else if (token_ != rbrace_)
+ {
+ buffering_ = false;
+ }
+ }
+ }
+
+ public:
+ virtual Void
+ unbuffer ()
+ {
+ AsInt result;
+
+ while (!hold_.empty ())
+ {
+ result = out_.put (hold_.front ());
+
+ //@@ failed
+ if (result == Traits::eof ())
+ throw Write ();
+
+ hold_.pop_front ();
+ }
+ }
+
+ private:
+ Void
+ ensure_new_line ()
+ {
+ if (hold_.empty () || hold_.back () != '\n')
+ {
+ hold_.push_back ('\n');
+ position_ = 0; // Starting a new line.
+ }
+ }
+
+
+ Void
+ output_indentation ()
+ {
+ if (!hold_.empty () && hold_.back () == '\n')
+ {
+ for (UnsignedLong i (0); i < indentation_.top (); ++i)
+ write (' ');
+
+ position_ += indentation_.top ();
+ }
+ }
+
+ AsInt
+ write (AsChar c)
+ {
+ hold_.push_back (c);
+
+ if (!buffering_)
+ {
+ AsInt result (Traits::eof ());
+
+ while (!hold_.empty ())
+ {
+ result = out_.put (hold_.front ());
+
+ if (result == Traits::eof ())
+ throw Write ();
+
+ hold_.pop_front ();
+ }
+
+ return result;
+ }
+ else
+ return c;
+ }
+
+ private:
+ struct Construct
+ {
+ enum Value
+ {
+ other,
+ pp_directive,
+ c_comment,
+ cxx_comment,
+ string_literal,
+ char_literal
+ };
+ };
+
+ Void
+ tokenize (AsChar c, typename Construct::Value old)
+ {
+ //
+ //
+ switch (construct_)
+ {
+ case Construct::pp_directive:
+ {
+ if (old == Construct::other) // Start PP directive
+ retire (c);
+
+ return;
+ }
+ case Construct::c_comment:
+ {
+ if (old == Construct::other) // Start C comment.
+ lexeme_.clear ();
+
+ return;
+ }
+ case Construct::cxx_comment:
+ {
+ if (old == Construct::other) // Start C++ comment.
+ lexeme_.clear ();
+
+ return;
+ }
+ case Construct::string_literal:
+ {
+ if (old == Construct::other) // Start string literal
+ retire (c);
+
+ lexeme_ += c;
+ return;
+ }
+ case Construct::char_literal:
+ {
+ if (old == Construct::other) // Start char literal
+ retire (c);
+
+ lexeme_ += c;
+ return;
+ }
+ default:
+ break;
+ }
+
+ // construct_ == other
+ //
+ switch (old)
+ {
+ case Construct::pp_directive:
+ {
+ // End PP directive (newline).
+ //
+ return;
+ }
+ case Construct::c_comment:
+ {
+ // End C comment.
+ //
+ return;
+ }
+ case Construct::cxx_comment:
+ {
+ // End C++ comment (newline).
+ //
+ return;
+ }
+ case Construct::string_literal:
+ {
+ // End string literal (").
+ //
+ lexeme_ += c;
+ return;
+ }
+ case Construct::char_literal:
+ {
+ // End char literal (').
+ //
+ lexeme_ += c;
+ return;
+ }
+ default:
+ break;
+ }
+
+
+ // construct_ == old == other
+ //
+
+ /*
+
+ The code below is equivalent to this (simpler) code which is
+ unfortunately not fast enough.
+
+ using std::isalpha;
+ using std::isalnum;
+ using std::isdigit;
+ using std::isspace;
+
+ if (c == '_' || isalpha (c, locale_))
+ {
+ if (lexeme_.empty () ||
+ lexeme_[0] == '_' || isalpha (lexeme_[0], locale_))
+ lexeme_ += c;
+ else
+ {
+ retire (c);
+ lexeme_ += c;
+ }
+ }
+ else if (isdigit (c, locale_))
+ {
+ if (lexeme_.empty () ||
+ lexeme_[0] == '_' || isalnum (lexeme_[0], locale_))
+ lexeme_ += c;
+ else
+ {
+ retire (c);
+ lexeme_ += c;
+ }
+ }
+ else // Delimiters
+ {
+ retire (c);
+
+ if (!isspace (c, locale_))
+ lexeme_ += c;
+ }
+ */
+
+ switch (char_class (c))
+ {
+ case CharClass::alpha:
+ {
+ if (lexeme_.empty () ||
+ char_class (lexeme_[0]) == CharClass::alpha)
+ lexeme_ += c;
+ else
+ {
+ retire (c);
+ lexeme_ += c;
+ }
+ break;
+ }
+ case CharClass::digit:
+ {
+ if (lexeme_.empty ())
+ lexeme_ += c;
+ else
+ {
+ typename CharClass::Value cc (char_class (lexeme_[0]));
+
+ if (cc == CharClass::alpha || cc == CharClass::digit)
+ lexeme_ += c;
+ else
+ {
+ retire (c);
+ lexeme_ += c;
+ }
+ }
+ break;
+ }
+ case CharClass::op_punc:
+ {
+ retire (c);
+ lexeme_ += c;
+ break;
+ }
+ case CharClass::space:
+ {
+ retire (c);
+ break;
+ }
+ }
+ }
+
+ struct CharClass
+ {
+ enum Value
+ {
+ alpha, // Alpha + '_'.
+ digit,
+ op_punc, // Operator or punctuation.
+ space
+ };
+
+ };
+
+ typename CharClass::Value
+ 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 CharClass::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 CharClass::op_punc;
+
+ case ' ':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\r':
+ case '\v':
+ return CharClass::space;
+
+ default:
+ return CharClass::alpha;
+ }
+ }
+
+
+ Void
+ retire (AsChar c)
+ {
+ if (!lexeme_.empty ())
+ {
+ token_.swap (lexeme_);
+ next_token (lexeme_, c);
+ lexeme_.clear ();
+ }
+ }
+
+ private:
+ Buffer<C>& out_;
+ Boolean buffering_; // True if write() should buffer the char.
+ UnsignedLong position_; // Current position on the line.
+ UnsignedLong paren_balance_; // ( ) balance.
+ Cult::Containers::Stack<UnsignedLong> indentation_;
+ UnsignedLong spaces_;
+
+ Boolean suppress_nl_;
+
+ //@@ gcc bug# 18304
+ //
+ typename Construct::Value construct_;
+
+ // Special state stach 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.
+ Cult::Containers::Stack<UnsignedLong> do_while_state_;
+
+ typedef
+ Cult::Containers::Deque<AsInt>
+ Hold;
+
+ Hold hold_;
+
+ private:
+ String token_; // previously fully recognized token
+ String lexeme_; // current lexeme (accumulator)
+
+ // std::locale locale_;
+
+ // Keywords that may be folowed by a single-line block, e.g., if,
+ // else, etc.
+ //
+ Cult::Containers::Set<String> single_line_blocks_;
+
+ // Keywords that may follow (and be related) to a previous block,
+ // e.g., else, case, catch.
+ //
+ Cult::Containers::Set<String> follow_blocks_;
+
+ 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 IndentBlockInfo
+ {
+ IndentBlockInfo (Boolean newline, Boolean indented)
+ : newline_ (newline), indented_ (indented)
+ {
+ }
+
+ Boolean newline_;
+ Boolean indented_;
+ };
+
+ Cult::Containers::Stack<IndentBlockInfo> indent_block_;
+ };
+ }
+}
+
+#include <backend-elements/indentation/cxx.txx>
+
+#endif // BACKEND_ELEMENTS_INDENTATION_CXX_HXX
diff --git a/libbackend-elements/backend-elements/indentation/cxx.txx b/libbackend-elements/backend-elements/indentation/cxx.txx
new file mode 100644
index 0000000..9acff37
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/cxx.txx
@@ -0,0 +1,12 @@
+// file : backend-elements/indentation/cxx.txx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ }
+}
+
diff --git a/libbackend-elements/backend-elements/indentation/idl.hxx b/libbackend-elements/backend-elements/indentation/idl.hxx
new file mode 100644
index 0000000..e5a234f
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/idl.hxx
@@ -0,0 +1,290 @@
+// file : backend-elements/indentation/idl.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_INDENTATION_IDL_HXX
+#define BACKEND_ELEMENTS_INDENTATION_IDL_HXX
+
+#include <backend-elements/types.hxx>
+#include <backend-elements/indentation/buffer.hxx>
+
+#include <cult/containers/deque.hxx>
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ template <typename C>
+ class IDL: public Buffer<C>, public NonCopyable
+ {
+ public:
+ typedef
+ typename Buffer<C>::Traits
+ Traits;
+
+ typedef
+ typename Buffer<C>::AsChar
+ AsChar;
+
+ typedef
+ typename Buffer<C>::AsInt
+ AsInt;
+
+ typedef
+ typename Buffer<C>::Write
+ Write;
+
+ public:
+ IDL (Buffer<C>& out)
+ : out_ (out),
+ indentation_ (0),
+ spaces_ (2),
+ construct_ (Construct::other)
+ {
+ }
+
+ public:
+ virtual AsInt
+ put (AsChar c)
+ {
+ AsInt result (Traits::to_int_type (c));
+
+ try
+ {
+ Boolean defaulting (false);
+
+ switch (c)
+ {
+ case '\n':
+ {
+ hold_.push_back (c);
+ break;
+ }
+ case '{':
+ {
+ ensure_new_line ();
+ output_indentation ();
+ result = write (c);
+ ensure_new_line ();
+ indentation_++;
+ break;
+ }
+ case '}':
+ {
+ if (indentation_ > 0) indentation_--;
+
+ // Reduce multiple newlines to one.
+ //
+ while (hold_.size () > 1)
+ {
+ typename Hold::ReverseIterator 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');
+
+
+ break;
+ }
+ case ';':
+ {
+ // Handling '};' case.
+ //
+
+ Boolean brace (false);
+
+ if (hold_.size () > 1 && hold_.back () == '\n')
+ {
+ Boolean pop_nl (false);
+
+ for (typename Hold::ReverseIterator
+ 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 ();
+ result = write (c);
+
+ if (brace)
+ {
+ hold_.push_back ('\n');
+ hold_.push_back ('\n');
+ }
+
+ if (construct_ != Construct::string_literal &&
+ construct_ != Construct::char_literal)
+ {
+ ensure_new_line ();
+ }
+ break;
+ }
+ case '\\':
+ {
+ hold_.push_back (c);
+ break;
+ }
+ case '\"':
+ {
+ if (hold_.empty () || hold_.back () != '\\')
+ {
+ // not escape sequence
+ if (construct_ == Construct::string_literal)
+ {
+ construct_ = Construct::other;
+ }
+ else construct_ = Construct::string_literal;
+ }
+
+ defaulting = true;
+ break;
+ }
+ case '\'':
+ {
+ if (hold_.empty () || hold_.back () != '\\')
+ {
+ // not escape sequence
+ if (construct_ == Construct::char_literal)
+ {
+ construct_ = Construct::other;
+ }
+ else construct_ = Construct::char_literal;
+ }
+
+ defaulting = true;
+ break;
+ }
+ default:
+ {
+ defaulting = true;
+ break;
+ }
+ }
+
+ if (defaulting)
+ {
+ output_indentation ();
+ result = write (c);
+ }
+ }
+ catch (Write const&)
+ {
+ result = Traits::eof ();
+ }
+
+ return result;
+ }
+
+ virtual Void
+ unbuffer ()
+ {
+ AsInt result;
+
+ while (!hold_.empty ())
+ {
+ result = out_.put (hold_.front ());
+
+ //@@ failed
+ if (result == Traits::eof ())
+ throw Write ();
+
+ hold_.pop_front ();
+ }
+ }
+
+ private:
+ Void
+ ensure_new_line ()
+ {
+ if (hold_.empty () || hold_.back () != '\n')
+ hold_.push_back ('\n');
+ }
+
+
+ Void
+ output_indentation ()
+ {
+ if (!hold_.empty () && hold_.back () == '\n')
+ for (UnsignedLong i (0); i < indentation_ * spaces_; ++i)
+ write (' ');
+ }
+
+ AsInt
+ write (AsChar c)
+ {
+ hold_.push_back (c);
+
+ AsInt result (Traits::eof ());
+
+ while (!hold_.empty ())
+ {
+ result = out_.put (hold_.front ());
+
+ if (result == Traits::eof ())
+ throw Write ();
+
+ hold_.pop_front ();
+ }
+
+ return result;
+ }
+
+
+ private:
+
+ Buffer<C>& out_;
+ UnsignedLong indentation_;
+ UnsignedLong spaces_;
+
+ Boolean suppress_nl_;
+
+ struct Construct
+ {
+ enum Value
+ {
+ other,
+ string_literal,
+ char_literal
+ };
+ };
+
+ //@@ gcc bug# 18304
+ //
+ typename Construct::Value construct_;
+
+ typedef
+ Cult::Containers::Deque<AsInt>
+ Hold;
+
+ Hold hold_;
+ };
+ }
+}
+
+#include <backend-elements/indentation/idl.txx>
+
+#endif // BACKEND_ELEMENTS_INDENTATION_IDL_HXX
diff --git a/libbackend-elements/backend-elements/indentation/idl.txx b/libbackend-elements/backend-elements/indentation/idl.txx
new file mode 100644
index 0000000..6ddc63e
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/idl.txx
@@ -0,0 +1,11 @@
+// file : backend-elements/indentation/idl.txx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ }
+}
diff --git a/libbackend-elements/backend-elements/indentation/sloc.hxx b/libbackend-elements/backend-elements/indentation/sloc.hxx
new file mode 100644
index 0000000..57e6989
--- /dev/null
+++ b/libbackend-elements/backend-elements/indentation/sloc.hxx
@@ -0,0 +1,277 @@
+// file : backend-elements/indentation/sloc.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_INDENTATION_SLOC_HXX
+#define BACKEND_ELEMENTS_INDENTATION_SLOC_HXX
+
+#include <backend-elements/types.hxx>
+#include <backend-elements/indentation/buffer.hxx>
+
+#include <cctype>
+#include <iostream> //@@ tmp
+
+namespace BackendElements
+{
+ namespace Indentation
+ {
+ template <typename C>
+ class SLOC: public Buffer<C>/*, public NonCopyable*/
+ {
+ public:
+ typedef
+ typename Buffer<C>::Traits
+ Traits;
+
+ typedef
+ typename Buffer<C>::AsChar
+ AsChar;
+
+ typedef
+ typename Buffer<C>::AsInt
+ AsInt;
+
+ typedef
+ typename Buffer<C>::Write
+ Write;
+
+ public:
+ SLOC (Buffer<C>& out)
+ : out_ (out),
+ count_ (0),
+ prev_ ('\0'),
+ code_counted_ (false),
+ construct_ (Construct::code)
+ {
+ }
+
+ UnsignedLong
+ count () const
+ {
+ return count_;
+ }
+
+ public:
+ virtual AsInt
+ put (AsChar c)
+ {
+ typename Construct::Value old (construct_);
+
+ switch (construct_)
+ {
+ case Construct::code:
+ {
+ code (c);
+ break;
+ }
+ case Construct::c_comment:
+ {
+ c_comment (c);
+ break;
+ }
+ case Construct::cxx_comment:
+ {
+ cxx_comment (c);
+ break;
+ }
+ case Construct::char_literal:
+ {
+ char_literal (c);
+ break;
+ }
+ case Construct::string_literal:
+ {
+ 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';
+
+ return out_.put (c);
+ }
+
+ virtual Void
+ unbuffer ()
+ {
+ }
+
+ private:
+ Void
+ code (AsChar c)
+ {
+ bool count (true);
+
+ switch (c)
+ {
+ case '/':
+ {
+ if (prev_ == '/')
+ {
+ construct_ = Construct::cxx_comment;
+ 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_ = Construct::c_comment;
+ count = false;
+ }
+ break;
+ }
+ case '\'':
+ {
+ construct_ = Construct::char_literal;
+ break;
+ }
+ case '"':
+ {
+ construct_ = Construct::string_literal;
+ break;
+ }
+ case '\n':
+ {
+ code_counted_ = false; // reset for a new line
+ count = false;
+ break;
+ }
+ default:
+ {
+ if (std::isspace (c))
+ count = false;
+ break;
+ }
+ }
+
+ // The second condition here accounts for the fact that we cannot
+ // count '/' right away since it can be a beginning of a comment.
+ //
+ if (!code_counted_ &&
+ (count || (prev_ == '/' && construct_ == Construct::code)))
+ {
+ //std::wcerr << "detected code @ " << c << std::endl;
+ count_++;
+ code_counted_ = true;
+ }
+ }
+
+ Void
+ c_comment (AsChar c)
+ {
+ switch (c)
+ {
+ case '/':
+ {
+ if (prev_ == '*')
+ construct_ = Construct::code;
+ break;
+ }
+ case '\n':
+ {
+ code_counted_ = false; // reset for a new line
+ break;
+ }
+ }
+ }
+
+ Void
+ cxx_comment (AsChar c)
+ {
+ switch (c)
+ {
+ case '\n':
+ {
+ construct_ = Construct::code;
+ code_counted_ = false; // reset for a new line
+ break;
+ }
+ }
+ }
+
+ Void
+ char_literal (AsChar c)
+ {
+ switch (c)
+ {
+ case '\'':
+ {
+ if (prev_ != '\\')
+ construct_ = Construct::code;
+ break;
+ }
+ }
+ }
+
+ Void
+ string_literal (AsChar c)
+ {
+ switch (c)
+ {
+ case '"':
+ {
+ if (prev_ != '\\')
+ construct_ = Construct::code;
+ break;
+ }
+ case '\n':
+ {
+ /*@@ Should I count multi-line string literal as multiple SLOC? */
+ break;
+ }
+ }
+ }
+
+ private:
+ Buffer<C>& out_;
+ UnsignedLong count_;
+
+ AsChar prev_; // previous character or '\0'
+
+ struct Construct
+ {
+ enum Value
+ {
+ code,
+ c_comment,
+ cxx_comment,
+ char_literal,
+ string_literal
+ };
+ };
+
+ // code
+ //
+ bool code_counted_;
+
+ //@@ gcc bug# 18304
+ //
+ typename Construct::Value construct_;
+ };
+ }
+}
+
+//#include <backend-elements/indentation/sloc.txx>
+
+#endif // BACKEND_ELEMENTS_INDENTATION_SLOC_HXX
diff --git a/libbackend-elements/backend-elements/makefile b/libbackend-elements/backend-elements/makefile
new file mode 100644
index 0000000..70a3e4a
--- /dev/null
+++ b/libbackend-elements/backend-elements/makefile
@@ -0,0 +1,63 @@
+# file : backend-elements/makefile
+# author : Boris Kolpackov <boris@kolpackov.net>
+# copyright : Copyright (c) 2005-2010 Boris Kolpackov
+# license : GNU GPL v2; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
+
+cxx_tun :=
+cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o))
+cxx_od := $(cxx_obj:.o=.o.d)
+
+backend_elements.l := #$(out_base)/backend-elements.l
+backend_elements.l.cpp-options := $(out_base)/backend-elements.l.cpp-options
+
+clean := $(out_base)/.clean
+
+
+# Secure default target.
+#
+$(backend_elements.l.cpp-options):
+#$(backend_elements.l):
+
+
+# Imports.
+#
+$(call import,\
+ $(scf_root)/import/libcult/stub.make,\
+ l: cult.l,cpp-options: cult.l.cpp-options)
+
+$(call import,\
+ $(scf_root)/import/libboost/regex/stub.make,\
+ l: re.l,cpp-options: re.l.cpp-options)
+
+
+# Build.
+#
+#$(backend_elements.l): $(cxx_obj) $(cult.l)
+
+#$(cxx_obj): $(backend_elements.l.cpp-options)
+
+$(backend_elements.l.cpp-options): value := -I$(src_root)
+$(backend_elements.l.cpp-options): $(re.l.cpp-options) $(cult.l.cpp-options)
+
+#$(call include-dep,$(cxx_od))
+
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(backend_elements.l.cpp-options)
+
+
+# Clean.
+#
+#$(BackendElements.l).clean \
+
+$(clean): $(addsuffix .cxx.clean,$(cxx_obj)) \
+ $(backend_elements.l.cpp-options).clean
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-l.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
diff --git a/libbackend-elements/backend-elements/regex.hxx b/libbackend-elements/backend-elements/regex.hxx
new file mode 100644
index 0000000..9dc6024
--- /dev/null
+++ b/libbackend-elements/backend-elements/regex.hxx
@@ -0,0 +1,208 @@
+// file : backend-elements/regex.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_REGEX_HXX
+#define BACKEND_ELEMENTS_REGEX_HXX
+
+#include <ostream>
+
+#include <boost/regex.hpp>
+
+#include <backend-elements/types.hxx>
+
+namespace BackendElements
+{
+ namespace Regex
+ {
+ template <typename C>
+ struct Format
+ {
+ Format (StringTemplate<C> const& expression,
+ StringTemplate<C> const& description)
+ : expression_ (expression), description_ (description)
+ {
+ }
+
+ StringTemplate<C> const&
+ expression () const
+ {
+ return expression_;
+ }
+
+ StringTemplate<C> const&
+ description () const
+ {
+ return description_;
+ }
+
+ private:
+ StringTemplate<C> expression_;
+ StringTemplate<C> description_;
+ };
+
+ // Regex pattern.
+ //
+ template <typename C>
+ struct Pattern
+ {
+ Pattern ()
+ {
+ }
+
+ Pattern (Char const* p)
+ {
+ init (StringTemplate<C> (p));
+ }
+
+ Pattern (StringTemplate<C> const& p)
+ {
+ init (p);
+ }
+
+ Pattern&
+ operator= (Char const* p)
+ {
+ init (StringTemplate<C> (p));
+ return *this;
+ }
+
+ Pattern&
+ operator= (StringTemplate<C> const& p)
+ {
+ init (p);
+ return *this;
+ }
+
+ public:
+ Boolean
+ match (StringTemplate<C> const& s) const
+ {
+ return regex_match (s, pat_, boost::format_all);
+ }
+
+ StringTemplate<C>
+ merge (StringTemplate<C> const& sub,
+ StringTemplate<C> const& s,
+ Boolean first_only = false) const
+ {
+ if (first_only)
+ return regex_merge (
+ s, pat_, sub, boost::format_all | boost::format_first_only);
+ else
+ return regex_merge ( s, pat_, sub, boost::format_all);
+ }
+
+ public:
+ Boolean
+ empty () const
+ {
+ return pat_.empty ();
+ }
+
+ public:
+ boost::basic_regex<C> const&
+ impl_pattern () const
+ {
+ return pat_;
+ }
+
+ private:
+ Void
+ init (StringTemplate<C> const& r);
+
+ private:
+ boost::basic_regex<C> pat_;
+ };
+
+ template <typename C1, typename C2>
+ inline std::basic_ostream<C1>&
+ operator<< (std::basic_ostream<C1>& os, Pattern<C2> const& p)
+ {
+ return os << p.impl_pattern ().str ().c_str ();
+ }
+
+ // Regex expression: '/pattern/substitution/'.
+ //
+ template <typename C>
+ struct Expression
+ {
+ Expression ()
+ {
+ }
+
+ // Expression is of the form /regex/format/ where '/' can be
+ // replaced with any delimiter.
+ //
+ Expression (Char const* e)
+ {
+ init (StringTemplate<C> (e));
+ }
+
+ Expression (StringTemplate<C> const& e)
+ {
+ init (e);
+ }
+
+ Expression&
+ operator= (Char const* e)
+ {
+ init (StringTemplate<C> (e));
+ return *this;
+ }
+
+ Expression&
+ operator= (StringTemplate<C> const& e)
+ {
+ init (e);
+ return *this;
+ }
+
+ public:
+ Boolean
+ match (StringTemplate<C> const& s) const
+ {
+ return pat_.match (s);
+ }
+
+ StringTemplate<C>
+ merge (StringTemplate<C> const& s, Boolean first_only = false) const
+ {
+ return pat_.merge (sub_, s, first_only);
+ }
+
+ public:
+ const Pattern<C>&
+ pattern () const
+ {
+ return pat_;
+ }
+
+ const StringTemplate<C>&
+ substitution () const
+ {
+ return sub_;
+ }
+
+ public:
+ Boolean
+ empty () const
+ {
+ return pat_.empty () && sub_.empty ();
+ }
+
+ private:
+ Void
+ init (StringTemplate<C> const& r);
+
+ private:
+ Pattern<C> pat_;
+ StringTemplate<C> sub_;
+ };
+ }
+}
+
+#include <backend-elements/regex.txx>
+
+#endif // BACKEND_ELEMENTS_REGEX_HXX
diff --git a/libbackend-elements/backend-elements/regex.txx b/libbackend-elements/backend-elements/regex.txx
new file mode 100644
index 0000000..897e0e8
--- /dev/null
+++ b/libbackend-elements/backend-elements/regex.txx
@@ -0,0 +1,52 @@
+// file : backend-elements/regex.txx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+namespace BackendElements
+{
+ namespace Regex
+ {
+ template <typename C>
+ Void Pattern<C>::
+ init (StringTemplate<C> const& r)
+ {
+ try
+ {
+ pat_ = r;
+ }
+ catch (boost::regex_error const& e)
+ {
+ throw Format<C> (r, e.what ());
+ }
+ }
+
+ //
+ //
+ template <typename C>
+ Void Expression<C>::
+ init (StringTemplate<C> const& r)
+ {
+ typedef StringTemplate<C> String;
+
+ if (r.empty ())
+ throw Format<C> (r, "empty expression");
+
+ C d (r[0]);
+
+ Size first (0);
+ Size middle (r.find (d, first + 1));
+
+ if (middle == String::npos)
+ throw Format<C> (r, "missing second pattern-substitution separator");
+
+ Size last (r.find (d, middle + 1));
+
+ if (last == String::npos)
+ throw Format<C> (r, "missing third pattern-substitution separator");
+
+ pat_ = String (r, first + 1, middle - first - 1);
+ sub_.assign (r, middle + 1, last - middle - 1);
+ }
+ }
+}
diff --git a/libbackend-elements/backend-elements/types.hxx b/libbackend-elements/backend-elements/types.hxx
new file mode 100644
index 0000000..f309f5d
--- /dev/null
+++ b/libbackend-elements/backend-elements/types.hxx
@@ -0,0 +1,16 @@
+// file : backend-elements/types.hxx
+// author : Boris Kolpackov <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#ifndef BACKEND_ELEMENTS_TYPES_HXX
+#define BACKEND_ELEMENTS_TYPES_HXX
+
+#include <cult/types.hxx>
+
+namespace BackendElements
+{
+ using namespace Cult::Types;
+}
+
+#endif // BACKEND_ELEMENTS_TYPES_HXX