/*!
\page oess_1__ddl_format oess_1: Язык ObjESSty DDL

\section oess_1__ddl_format__purpose Назначение

Язык ObjESSty Data Definition Language (DDL) предназначен для описания
сериализуемых типов. Такие типы также называют устойчивыми, долговременными
или сохраняемыми (persistent). В свою очередь, сохраняемый тип состоит из
сохраняемых атрибутов. Не обязательно, чтобы все атрибуты сохраняемого
типа были сохраняемыми. Могут быть случаи, когда в типе нужно сохранять
всего один атрибут из числа всех его атрибутов. Могут быть так же
случаи, когда у типа нет ни одного сохраняемого атрибута -- это означает,
что тип будет использоваться в качестве вершины иерархии сохраняемых
типов. Атрибуты, которые не сериализуются, называются несохраняемыми
атрибутами (transient).

\section oess_1__ddl_format__common_format Общие сведения о формате DDL

За основу синаксиса DDL взят синтаксис языка программирования Curl
(http://www.curl.com). Поддержка DDL реализована с использованием библиотеки
Curl Like Syntax (cls_2, http://eao197.narod.ru/projects.htm#cls_2), поэтому
иногда употребляются термины cls_2-синтаксис или cls_2-формат.

\subsection oess_1__ddl_format__common_format__syntax Особенности синтаксиса DDL

DDL описание состоит из тегов. Каждый тег может содержать
токены и/или дочерние теги. Каждый тег начинается с открывающей
фигурной скобки, за которой без пробелов следует название тега.
Название может состоять из любых непробельных символов.

DDL описание может содержать комментарии, которые полностью
игнорируются при разборе. Существуют два вида коментариев:
- однострочный. Начинается с <tt>||</tt> и завершается в конце
строки;
- многострочный. Начинается с <tt>|#</tt> и завершается
<tt>#|</tt>.

Многострочные комментарии не могут быть вложенными друг в друга.

При разброре многострочные комментарии заменяются на один пробельный
символ. Однострочные комментации заменяются на один символ перевода
строки.

Значениями тега называются все токены, указанные внутри тега
без учета дочерных тегов. Различаются три типа токенов:
- \b space (пробелы). Содержат все пробельные символы между
двумя соседними токенами. Пробельными символами
являются: пробел, перевод строки ("\n"), возврат каретки
("\r"), горизонтальная табуляция ("\t");
- \b nonspace (не пробелы). Непрерывная последовательность
символов, отличных от пробелов;
- \b string (строка). Последовательность символов, заключенная
в двойные кавычки.

Разница между nonspace и string заключается в том, что внутри строки
могут содержаться пробелы. Поэтому строка должна обязательно
начинаться с двойной ковычки и закрываться двойной кавычкой.

Символы \b {, \b }, \b |, \b \\, \b " являются управляющими. Поэтому
их нельзя использовать непосредственно в токенах nonspace и string.
При необходимости использования этих значений необходим префиксовать
их с помощью обратного слеша. Например:
- \\{;
- \\};
- \\|;
- \\\\;
- \\".

Для того, чтобы двойная кавычка не открывала токен типа string достаточно
записать ее в виде escape-последовательности.

\b Примечание. Указанные выше управляющие символы обязательно
должны быть представлены в виде escape-последовательностей внутри
токена типа string.

Для записи любого символа можно использовать целочисленное значение
кода символа, представленное в одной из систем счисления:
- двоичной. Представление должно начинаться с префикса
\\b или \\B, за которым должно следовать восемь двоичных разрядов.
Например, \\b01000001;
- восьмеричной. Представление должно начинаться с префикса
\\o или \\O, за которым должно следовать три восьмеричных разряда.
Например, \\o017;
- шестнадцатиричной. Представление должно начинаться с префикса
\\x или \\X, за которым должно следовать два шестнадцатиричных разряда.
Например, \\xfb.

Так же поддерживаются следующие escape-последовательности:
- \\n -- перевод строки;
- \\r -- возврат каретки;
- \\t -- горизонтальная табуляция.

\subsection oess_1__ddl_format__common_format__ddl_description DDL описание схемы данных

DDL описание схемы данных представляет из себя текстовый файл, в котором
с помощью тегов <i>{type}</i> перечислены все сохраняемые типы. Не обязательно
помещать описание всей схемы данных всего приложения в один ddl-файл. Не
обязательно так же размещать в одном ddl-файле описания всех типов, которые
как-либо используют друг-друга. Если при обработке DDL описания ObjESSty
встречает неизвестное имя типа, то это не считается ошибкой.
В этом случае ObjESSty предполагает, что данный тип будет описан в другом
ddl-описании.

Основное назначение DDL-описания -- это генерация по нему вспомогательного
кода для стандартной схемы сериализации (см. oess_1::stdsn). Поэтому важно,
чтобы все типы были определены должным образом на уровне C++ описаний и кода,
а не на уровне DDL-описания. Так, когда ObjESSty встречает имя типа, ObjESSty 
использует это имя затем в сгенерированном C++ коде. Если при компиляции этого
кода тип оказывается неизвестным, то тогда программит должен определить,
что произошло. Если он указан неправильное имя типа в DDL описании, то
следует поправить DDL-описание. Если же имя типа правильное, то программист
должен подключить к вспомогательному коду все необходимые заголовочные
файлы.

\section oess_1__ddl_format__tag_type	Тег {type}

Каждый сохраняемый тип описывается тегом <i>{type}</i>, который имеет
вид:

\verbatim
{type <имя>
	[{abstract}]
	[{extensible}]
	[{subclassing_by_extension ...]}]
	[{super ...}]*
	[{attr ...}]*
	[{extension ...}]
	[{cpp-mapping ...}]
}
\endverbatim

<i>\<имя\></i> определяет имя типа в схеме данных. Оно не должно содержать
пробелов. Имя типа в схеме данных может отличаться от имени типа в С++. В этом
случае для генерации правильного вспомогательного кода реальное C++ имя типа
нужно указать в теге <i>{cpp-mapping {name}}</i> (\ref
oess_1__ddl_format__tag_cpp_mapping__tag_name).

Тег <i>{abstract}</i> должен быть указан, если С++ тип является абстрактным.
Этот тег предписывает ObjESSty не генерировать во вспомогательном коде
инструкций по инстанциированию объектов этого типа.
Объявленные абстрактными типы не могут затем использоваться в качестве
типов атрибутов-значений. Но они могут использоваться в качестве типов
атрибутов-указателей.

Тег <i>{extensible}</i> указывает, что тип является расширяемым и для него
может использоваться тег <i>{extension}</i>. Подробнее эти теги описанны
в \ref oess_1_2_0__extensible_types__ddl_decl.

Тег <i>{subclassing_by_extension}</i> используется для задействования
механизма subclassing by extension. Подробнее см.
\ref oess_1_2_0__subclassing_by_extension.

Тег <i>{super}</i> используется для перечисления базовых типов.
Подробнее см. \ref oess_1__ddl_format__tag_super.

Каждый тег <i>{attr}</i> должен описывать один сохраняемый атрибут.
Подробнее формат тега <i>{attr}</i> описан в
\ref oess_1__ddl_format__tag_attr.

Тег <i>{cpp-mapping}</i> описывает дополнительные параметры для
отображения типа в C++. Подробнее этот тег описан в
\ref oess_1__ddl_format__tag_cpp_mapping.

Все вышеперечисленные теги являются необязательными. Обязательным является
только имя типа.

Если C++ тип входит в какое-либо пространство имен, то его имя в
схеме данных должно быть либо полным именем типа (с учетом всех
пространств имен), либо должен использоваться тег
<i>{cpp_mapping {type}}</i>:

\code
namespace oess_1 {
namespace db {
namespace storage {
namespace impl {

class	stream_storage_dir_item_t
	:	public oess_1::stdsn::serializable_t
	{ ... }; 
...

class	stream_storage_dir_t
	:	public oess_1::stdsn::serializable_t
	{ ... };

} /* namespace impl */
} /* namespace storage */
} /* namespace db */
} /* namespace oess_1 */
\endcode

\verbatim
{type	oess_1::db::storage::impl::stream_storage_dir_item_t
	...
}

{type	oess_1::db::storage::impl::stream_storage_dir_t
	...
}
\endverbatim

Порядок следования тегов важен только для однотипных тегов. Так, важен
взаимный порядок следования тегов <i>{super}</i> и <i>{attr}</i>: в каком
порядке они указанны, в таком же порядке будет осуществляться сериализация
базовых типов и атрибутов.

\subsection oess_1__ddl_format__tag_super	Тег {type {super}}

Для каждого базового типа в описании сохраняемого типа должен быть
указан свой тег <i>{super}</i>, который имеет формат:

\verbatim
{super [{virtual}] [{public}] <имя>}
\endverbatim

<i>\<имя\></i> -- это имя базового типа в схеме данных (в C++ базовый тип может
иметь другое имя, см. \ref oess_1__ddl_format__tag_cpp_mapping__tag_name).

Тег <i>{virtual}</i> должен быть указан, если используется виртуальное
наследование.

Тег <i>{public}</i> зарезервирован. В настоящее время он не обрабатывается и
указывать его в описании не рекомендуется.

Тег <i>{super}</i> <b>не должен использоваться</b>, если тип унаследован
непосредственно от oess_1::stdsn::serializable_t.

\par Пример 1.
Следующему С++ типу:
\code
class	my_derived_t : public my_base_t
  { ... };
\endcode
должно соответствовать следующее описание:
\verbatim
{type	my_derived_t
	{super my_base_t}
	...
}
\endverbatim

\par Пример 2.
Следующему C++ типу:
\code
class my_derived_t : public virtual my_base_t
  { ... };
\endcode
должно соответствовать описание:
\verbatim
{type	my_derived_t
	{super {virtual} my_base_t}
	...
}
\endverbatim

\par Пример 3.
Следующему C++ типу:
\code
class my_derived_t
	: public my_base_t
	, protected my_protected_base_t
	, private my_private_base_t
  { ... };
\endcode
должно соответствовать описание:
\verbatim
{type	my_derived_t
	{super my_base_t}
	{super my_protected_base_t}
	{super my_private_base_t}
	...
}
\endverbatim

\subsection oess_1__ddl_format__tag_attr	Тег {type {attr}}

Для каждого сохраняемого атрибута в описании типа должен быть указан
тег <i>{attr}</i>, который имеет формат:

\verbatim
{attr <имя>
	[<тип контейнера>]
	{of [{ptr} | {extension_of}] <имя типа>}
	[{default {c++ <выражение 1>}
		[{present_if {c++ <выражение 2>}]
	}]
}
\endverbatim

<i>\<имя\></i> -- это имя сериализуемого атрибута. Должно использоваться
тоже самое имя, что и в C++ описании типа.

Тег <i>{of}</i> задает тип атрибута. В качестве <i>\<имя типа\></i> могут
использоваться либо имена других сериализуемых типов, либо имена
встроенных типов ObjESSty:
- oess_1::char_t, oess_1::schar_t, oess_1::uchar_t;
- oess_1::short_t, oess_1::ushort_t;
- oess_1::int_t, oess_1::uint_t;
- oess_1::single_t, oess_1::double_t;
- oess_1::ent_id_t;
- std::string.

Тег <i>{of {ptr}}</i> указывает, что типом является указатель на
указанный тип. Т.е. запись:
\verbatim
{attr a {of {ptr} A}}
\endverbatim
соответствует:
\code
A *	m_a;
\endcode

Тег <i>{of {extension_of}}</i> указывает, что типом является указатель на
тип, который использует механизм subclassing by extension (см. 
\ref oess_1_2_0__subclassing_by_extension).

Если атрибут является контейнером, то тип контейнера должен задаваться
одним из следующих тегов:
- <i>{stl-vector}</i>. Атрибут -- это std::vector объектов, тип которых
	задан в <i>{of}</i>;
- <i>{stl-list}</i>. Атрибут -- это std::list объектов, тип которых
	задан в <i>{of}</i>;
- <i>{stl-deque}</i>. Атрибут -- это std::deque объектов, тип которых
	задан в <i>{of}</i>;
- <i>{stl-set [{multi}]}</i>. Атрибут -- это std::set (если подтег
	<i>{multi}</i> не указан) или std::multiset (подтег <i>{multi}</i>
	указан) объектов, тип которых задан в <i>{of}</i>;
- <i>{stl-map [{multi}] {key \<тип ключа\>}}</i>. Атрибут -- это std::map
	(если подтег <i>{multi}</i>} не указан) или std::multimap
	(подтег <i>{multi}</i> указан) объектов, тип которых
	задан в <i>{of}</i>. Тип ключа задается в теге <i>{stl-map {key}}</i>;
- <i>{fixed-vector \<размерность\>}</i>. Атрибут -- это одномерный
	вектор объетов, тип которых задан в <i>{of}</i>. Размерность вектора
	задается параметром <i>\<размерность\></i>.

\note Для STL контейнеров должны использоваться предикаты сравнения и
аллокаторы по-умолчанию. Т.е. нельзя сериализовать std::set у которого
используется предика сравнения, отличный от std::less, или std::vector,
у которого используется собственный аллокатор.

Тег <i>{default}</i> задает значение атрибута по-умолчанию. Данный тег
нужно использовать, если атрибут является опциональным (см.
\ref oess_1_2_0__optional_fields) или входит в расширение типа
(см. \ref oess_1_2_0__extensible_types).

\par Пример 1.
C++ типу:
\code
class	my_type_t : public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( my_type_t )
	private :
		enum { data_capacity = 64 };

		int	m_i;
		float	m_f;
		char	m_data[ data_capacity ];
	...
	};
\endcode
должно соответствовать DDL описание:
\verbatim
{type	my_type_t
	{attr m_i {of oess_1::int_t}}
	{attr m_f {of oess_1::single_t}}
	{attr m_data
		|| DDL ничего не знает про C++ константы, поэтому
		|| размерность вектора должна быть указана явно.
		{fixed-vector 64}
		{of oess_1::char_t}}
}
\endverbatim

\par Пример 2.
Следующему C++ описанию:
\code
class event_key_t : public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( event_key_t )
	private :
		std::string	m_event_class;
		oess_1::uint_t	m_event_priority;
		...
	public :
		...
		bool
		operator<( const my_key_t & o ) const;
		...
};
class event_data_t : public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( event_data_t )
	private :
		std::multiset< oess_1::uint_t >	m_tickets;
		...
	};
class	dispatcher_t : public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( dispatcher_t )
	private :
		std::list< std::string >	m_event_sources;
		std::map< event_key_t, event_data_t >	m_pending_events;
		...
	};
\endcode
должно соответствовать DDL описание:
\verbatim
{type	event_key_t
	{attr m_event_class {of std::string}}
	{attr m_event_priority {of oess_1::uint_t}}
}
{type	event_data_t
	{attr m_tickets {stl-set {multi}} {of oess_1::uint_t}}
}
{type	dispatcher_t
	{attr m_event_sources {stl-list} {of std::string}}
	{attr m_pending_events
		{stl-map {key event_key_t}}
		{of event_data_t}}
}
\endverbatim

\subsection oess_1__ddl_format__tag_cpp_mapping	Тег {type {cpp-mapping}}

Тег <i>{cpp-mapping}</i> предназначен для указания генератору вспомогательного
кода дополнительной информации о том, как сериализуемый тип описан в C++.
Тег имеет формат:

\verbatim
{cpp-mapping [{name <имя типа>}]}
\endverbatim

\subsubsection oess_1__ddl_format__tag_cpp_mapping__tag_name	Тег {type {cpp-mapping {name}}}

Тег <i>{cpp-mapping {name}}</i> задает реальное имя сериализуемого типа
в C++. Это может потребоваться, если по каким-либо причинам имя типа в DDL
не совпадает с именем типа в C++. Например, из-за эволюции схемы данных.

Если в <i>{cpp-mapping {name}}</i> задано имя C++ типа, то это имя используется
для генерации вспомогательного кода.

\par Пример.
Пусть изначально сериализуемый тип не принадлежал никакому пространству имен:
\verbatim
{type	event_dispatcher_info_t
	...
}
\endverbatim
Но с развитием проекта возникла потребность перенести event_dispatcher_info_t
в специальное пространство имен scheduling::core. Для того, чтобы не потерять
совместимости с уже сериализованными данными (в которых может быть
зафиксированно имя event_dispatcher_info_t, а не
scheduling::core::event_dispatcher_info_t), в DDL имя типа сохраняется, но
указывается, что в C++ этот тип имеет другое имя:
\verbatim
{type event_dispatcher_info_t
	...
	{cpp-mapping
		{name scheduling::core::event_dispatcher_info_t}}
}
\endverbatim

*/
