DDL описание может содержать комментарии, которые полностью игнорируются при разборе. Существуют два вида коментариев:
||
и завершается в конце строки;|#
и завершается #|
.Многострочные комментарии не могут быть вложенными друг в друга.
При разброре многострочные комментарии заменяются на один пробельный символ. Однострочные комментации заменяются на один символ перевода строки.
Значениями тега называются все токены, указанные внутри тега без учета дочерных тегов. Различаются три типа токенов:
Разница между nonspace и string заключается в том, что внутри строки могут содержаться пробелы. Поэтому строка должна обязательно начинаться с двойной ковычки и закрываться двойной кавычкой.
Символы {, }, |, \, " являются управляющими. Поэтому их нельзя использовать непосредственно в токенах nonspace и string. При необходимости использования этих значений необходим префиксовать их с помощью обратного слеша. Например:
Для того, чтобы двойная кавычка не открывала токен типа string достаточно записать ее в виде escape-последовательности.
Примечание. Указанные выше управляющие символы обязательно должны быть представлены в виде escape-последовательностей внутри токена типа string.
Для записи любого символа можно использовать целочисленное значение кода символа, представленное в одной из систем счисления:
Так же поддерживаются следующие escape-последовательности:
Основное назначение DDL-описания -- это генерация по нему вспомогательного кода для стандартной схемы сериализации (см. oess_1::stdsn). Поэтому важно, чтобы все типы были определены должным образом на уровне C++ описаний и кода, а не на уровне DDL-описания. Так, когда ObjESSty встречает имя типа, ObjESSty использует это имя затем в сгенерированном C++ коде. Если при компиляции этого кода тип оказывается неизвестным, то тогда программит должен определить, что произошло. Если он указан неправильное имя типа в DDL описании, то следует поправить DDL-описание. Если же имя типа правильное, то программист должен подключить к вспомогательному коду все необходимые заголовочные файлы.
{type <имя> [{abstract}] [{extensible}] [{subclassing_by_extension ...]}] [{super ...}]* [{attr ...}]* [{extension ...}] [{cpp-mapping ...}] }
<имя> определяет имя типа в схеме данных. Оно не должно содержать пробелов. Имя типа в схеме данных может отличаться от имени типа в С++. В этом случае для генерации правильного вспомогательного кода реальное C++ имя типа нужно указать в теге {cpp-mapping {name}} (Тег {type {cpp-mapping {name}}}).
Тег {abstract} должен быть указан, если С++ тип является абстрактным. Этот тег предписывает ObjESSty не генерировать во вспомогательном коде инструкций по инстанциированию объектов этого типа. Объявленные абстрактными типы не могут затем использоваться в качестве типов атрибутов-значений. Но они могут использоваться в качестве типов атрибутов-указателей.
Тег {extensible} указывает, что тип является расширяемым и для него может использоваться тег {extension}. Подробнее эти теги описанны в Описание расширяемых типов на DDL.
Тег {subclassing_by_extension} используется для задействования механизма subclassing by extension. Подробнее см. oess_1.2.0. Наследование расширением (subclassing_by_extension).
Тег {super} используется для перечисления базовых типов. Подробнее см. Тег {type {super}}.
Каждый тег {attr} должен описывать один сохраняемый атрибут. Подробнее формат тега {attr} описан в Тег {type {attr}}.
Тег {cpp-mapping} описывает дополнительные параметры для отображения типа в C++. Подробнее этот тег описан в Тег {type {cpp-mapping}}.
Все вышеперечисленные теги являются необязательными. Обязательным является только имя типа.
Если C++ тип входит в какое-либо пространство имен, то его имя в схеме данных должно быть либо полным именем типа (с учетом всех пространств имен), либо должен использоваться тег {cpp_mapping {type}}:
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 */
{type oess_1::db::storage::impl::stream_storage_dir_item_t ... } {type oess_1::db::storage::impl::stream_storage_dir_t ... }
Порядок следования тегов важен только для однотипных тегов. Так, важен взаимный порядок следования тегов {super} и {attr}: в каком порядке они указанны, в таком же порядке будет осуществляться сериализация базовых типов и атрибутов.
{super [{virtual}] [{public}] <имя>}
<имя> -- это имя базового типа в схеме данных (в C++ базовый тип может иметь другое имя, см. Тег {type {cpp-mapping {name}}}).
Тег {virtual} должен быть указан, если используется виртуальное наследование.
Тег {public} зарезервирован. В настоящее время он не обрабатывается и указывать его в описании не рекомендуется.
Тег {super} не должен использоваться, если тип унаследован непосредственно от oess_1::stdsn::serializable_t.
class my_derived_t : public my_base_t { ... };
{type my_derived_t {super my_base_t} ... }
class my_derived_t : public virtual my_base_t { ... };
{type my_derived_t {super {virtual} my_base_t} ... }
class my_derived_t : public my_base_t , protected my_protected_base_t , private my_private_base_t { ... };
{type my_derived_t {super my_base_t} {super my_protected_base_t} {super my_private_base_t} ... }
{attr <имя> [<тип контейнера>] {of [{ptr} | {extension_of}] <имя типа>} [{default {c++ <выражение 1>} [{present_if {c++ <выражение 2>}] }] }
<имя> -- это имя сериализуемого атрибута. Должно использоваться тоже самое имя, что и в C++ описании типа.
Тег {of} задает тип атрибута. В качестве <имя типа> могут использоваться либо имена других сериализуемых типов, либо имена встроенных типов ObjESSty:
Тег {of {ptr}} указывает, что типом является указатель на указанный тип. Т.е. запись:
{attr a {of {ptr} A}}
A * m_a;
Тег {of {extension_of}} указывает, что типом является указатель на тип, который использует механизм subclassing by extension (см. oess_1.2.0. Наследование расширением (subclassing_by_extension)).
Если атрибут является контейнером, то тип контейнера должен задаваться одним из следующих тегов:
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 ]; ... };
{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}} }
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; ... };
{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}} }
{cpp-mapping [{name <имя типа>}]}
Если в {cpp-mapping {name}} задано имя C++ типа, то это имя используется для генерации вспомогательного кода.
{type event_dispatcher_info_t ... }
{type event_dispatcher_info_t ... {cpp-mapping {name scheduling::core::event_dispatcher_info_t}} }