summaryrefslogtreecommitdiff
path: root/libbackend-elements/backend-elements/indentation/idl.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbackend-elements/backend-elements/indentation/idl.hxx')
-rw-r--r--libbackend-elements/backend-elements/indentation/idl.hxx290
1 files changed, 290 insertions, 0 deletions
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