Формальное описание синтаксиса атрибута Citeck Records

Терминология

  • Контекст - область, которая выделена с помощью скобок или кавычек {}, [], (), "", '' или не выделена ничем (корневая область или корневой контекст);

  • Алиас - псевдоним для атрибута. Пример: в конструкции someAlias:name someAlias является алиасом и возможный результат вычисления - someAlias:"Договор №2";

  • Экранирование символа - добавление перед символом знака \. Необходимо в тех случаях, когда спец-символ должен быть обработан как обычный символ;

  • Спец-символ - символ, который в определенном контексте имеет специальное значение.

  • Скаляр - конечный атрибут, который не может содержать вложенных атрибутов. Может быть одним из ?id, ?str, ?disp, ?num, ?assoc, ?localId, ?bool, ?json.

Примечание

  1. Экранирование спец-символов необходимо только в текущем контексте и не требуется во вложенных контекстах.

Описание

Общий вид атрибута:

path0[].path1{INNER}|proc0(arg0,arg1)|proc1(arg0,arg1) (1)

path0[].path1 - это путь из атрибутов. Элементы пути объединяются через точку. Если точка является частью имени атрибута, то её следует экранировать.

Все атрибуты в пути кроме последнего имеют ровно один внутренний атрибут без пост-процессоров и алиаса. Последний атрибут в пути может иметь любое количество вложенных атрибутов, но не имеет алиаса. Все атрибуты в пути кроме первого не имеют пост-процессоров. Первый атрибут в пути может иметь любое количество пост-процессоров, которые указываются в конце после {INNER}. Любой элемент пути из атрибутов может иметь окончание [], которое при наличии означает, что атрибут множественный.

{INNER} содержит вложенные атрибуты с алиасами, которые разделены через запятую. Алиас не обязателен. Если он отсутствует, то для результата используется первое имя в пути атрибутов.

Пример значения {INNER}:

{alias0:attribute0,alias1:attribute1,attribute2}

В aliasN спец-символами являются , и :. Вместо attributeN допускается синтаксис (1), но c экранированием запятых , и если отсутствует алиас, то следует экранировать : (см. Примечание 1). Если алиас равен первому элементу в пути атрибутов, то это равнозначно отсутствию алиаса.

Вместо {INNER} при наличии только одного вложенного атрибута без алиаса и процессоров допускается запись без фигурных скобок. В таком случае если вложенный атрибут не является скаляром, то перед ним добавляется точка. Перед скаляром ничего не добавляется т.к. он уже содержит разделительный символ ?.

Примеры:

name?str == name{?str}
name.title?str == name{title{?str}}

Если атрибут заканчивается на скаляр ?disp (att0?disp или att0{?disp}), то допускается опустить окончание ?disp в атрибуте т.к. это скаляр по-умолчанию.

Пример:

name?disp == name

При описании атрибута допускается использование пост-процессоров, которые вызываются с результатом вычисления атрибута:

proc0(arg0,arg1)
  • procN - имя пост-процессора;

  • argN - аргументы, которые отделяются друг от друга запятыми. Допускаются значения аналогичные формату json - https://www.json.org/json-en.html , но с возможностью использовать для строк одинарные кавычки вместо двойных;

Пост-процессоры объединяются через символ | и выполняются слева направо аналогично unix pipeline. Пост-процессоры могут быть частью любого атрибута на любом уровне вложенности.

Для пост-процессора с типом «or» доступен дополнительный синтаксис с использованием !. Возможные варианты значения после !:

  1. Значение в двойных или одинарных кавычках означает константную строку; (some!'constant' == some|or('constant'))

  2. При отсутствии значения парсер подбирает нужный аргумент в зависимости от скаляра перед знаком !:

  • ?bool! -> false

  • ?json! -> {};

  • ?num! -> 0;

  • иначе -> "".

  1. null означает пустое значение; (some!null == some|or(null))

  2. true или false - булево значение; (some!true == some|or(true))

  3. Если первый символ число - числовое значение; (some!123 == some|or(123))

  4. Если ни один из вышестоящих вариантов не подошел, то считается, что указано имя атрибута, который нужно вернуть в случае если результат вычисления атрибута до ! оказался null; (some!other == some|or('a:other'))

Между частями атрибута (алиас, путь, вложенные атрибуты, пост-процессоры, аргументы) допускается использование любого количества пробельных символов (\n, \t, \r, ).

Модель атрибута:

SchemaAtt {
    alias: String,
    name: String,
    multiple: Boolean,
    inner: List<SchemaAtt>,
    processors: List<AttProcDef>
}

Модель пост-процессора:

AttProcDef {
    type: String,
    arguments: List<DataValue>
}