# Описание типа данных
## Пример
```
data MyType<data Magic, const WithContent> {
magic: Magic,
if 'eq(WithContent, 1) {
length: bytes<8, little> at magic.part@end shift 0,
body: bytes<length, little>,
},
}
```
## Грамматика в EBNF
```ebnf
Data = "data" ID "<" Comma<DataParam> ">" "{" Comma<DataStmt> "}" |
"data" ID "{" Comma<DataStmt> "}";
DataParam = "const" ID |
"data" ID |
"endianness" ID ;
DataStmt = ID ":" ID [ AtModifier ] [ ShiftModifier ] |
ID ":" ID "<" DataExpr ">" [ AtModifier ] [ ShiftModifier ] |
"if" SmtExpr "{" Comma<DataStmt> "}" ;
DataExpr = BitVecLiteral |
BitVecOp "(" Comma<SmtExpr> ")" |
ID "(" Comma<SmtExpr> ")" |
ID |
ID "<" Comma<DataExpr> ">" |
Endianness;
AtModifier = "at" Dot<ID> "@" LocationAnchor | "at" Dot<ID> ;
ShiftModifier = "shift" SmtExpr ;
LocationAnchor = "start" | "end" ;
Endianness = "little" | "big";
```
## Описание грамматики
### Data
```
Data:
"data" ID "<" Comma<DataParam> ">" "{" Comma<DataStmt> "}"
"data" ID "{" Comma<DataStmt> "}"
DataParam = "const" ID
"data" ID
"endianness" ID
```
Нетерминал, соответсвующий всему блоку описания типа данных. Первый вариант соответствует параметрическому типу. Второй — непараметрическому.
Нетерминал `DataParam` соответствует описанию одного параметра типа данных. Три его варианта соответствуют параметрам типа константа, тип данных и порядок байт.
Сответствующая AST-нода `data::Data` хранит в себе строку с именем, список параметром `data::Param` и список выражений `data::Statement`, являющийся телом определения данного типа.
AST-нода `data::Param` хранит в себе имя данного параметра.
### DataStmt
```
DataStmt:
ID ":" ID [ AtModifier ] [ ShiftModifier ]
ID ":" ID "<" Comma<DataExpr> ">" [ AtModifier ] [ ShiftModifier ]
"if" SmtExpr "{" Comma<DataStmt> "}"
```
Нетерминал соответствует одному выражению в теле определения типа. Три его варианта представляют из себя определение одного поля типа (`datamodel::Relation`) без параметров или с ними, или условного набора других выражений.
В первых двух случаях нетерминал `ID` соответствует тому типу, на который ссылается данный `Relation`. Во втором случае нетерминал `DataExpr` описывает параметры этого типа.
Имеются так же два опциональных модификатора: `AtModifier` и `ShiftModifier`, отвечающие соответственно за `Relation::Location` и `Relation::offset`.
В третьем случае выражение `SmtExpr` задает условие наличия вложенного выражения. Если вложенное выражение так же представляет из себя условное выражение, условия логически умножаются. В противном случае это условие задает `Relation::condition`.
AST-нода хранит в себе:
* в первых двух вариантах строку имени, строку типа, вектор его параметров `data::Expr` (в первом случае пустой) на который ссылается поле, опциональные модификаторы `data::AtModifier` и `data::ShiftModifier`;
* в третьем варианте условие `SmtExpr` и входящие в его тело выражения `data::Statement`.
### DataExpr
По сути представляет из себя модификацию SmtExpr. Этот нетерминал описывает возможные параметры типа. Он может соответствовать констатным параметрам, а так же другим (возможно параметризированным) типам или параметрам порядка байтов.
```
DataExpr:
BitVecLiteral
BitVecOp "(" Comma<SmtExpr> ")"
ID "(" Comma<SmtExpr> ")"
ID
ID "<" Comma<DataExpr> ">"
Endianness
```
Нетерминал расширяет нетерминал `SmtExpr` двумя последними вариантами. Первый из них соответствует описанию другого типа. Второй — описанию порядка байтов.
### AtModifier
```
AtModifier:
"at" Dot<ID> "@" LocationAnchor
"at" Dot<ID>
```
Нетерминал соответствует модификатору, отвечающему за `Location` соответствующего `Relation`. Второй вариант соответствует первому с параметром `LocationAnchor` равном `end` (значение по умолчанию).
Соответствующая AST-нода хранит в себе вектор строк — `LocationOrigin` и enum `LocationAnchor`.
### ShiftModifier
```
ShiftModifier:
"shift" SmtExpr
```
Нетерминал соответствует модификатору `Relation::offset`. AST-нода хранит в себе одно значение: `SmtExpr`.