Files
revng-revng/include/revng/Model/README.md
2024-06-27 11:05:49 +02:00

178 lines
4.3 KiB
Markdown

## tuple_tree_generator HOWTO
tuple_tree_generator takes a description of a struct/enum and generates boilerplate required to make them YAML
serializable/deserializable, compatible with `KeyedObjectContainer`s, and so on.
This document explains how to add an enum or a class to rev.ng model.
Remember to add the new header file to the `MODEL_HEADERS` list in `include/revng/Model/CMakeLists.txt`.
**Note**: Never include the generated headers anywhere apart from the one file containing the YAML that generated it.
Other files should include the header containing the YAML.
### Defining an enum
Enums can be defined like this
`<Name>.h` (the filename must match the name of the generated enum)
```cpp
#pragma once
// <copyright notice>
// Note: the TUPLE-TREE-YAML delimiter is mandatory
/* TUPLE-TREE-YAML
name: <Name>
type: enum
doc: <Optional documentation about the enum itself>
members:
- name: <Member_1_Name>
- name: <Member_2_Name>
doc: <Optional documentation about the specific enum member>
TUPLE-TREE-YAML */
#include "revng/Model/Generated/Early/<Name>.h"
// <other definitions>
#include "revng/Model/Generated/Late/<Name>.h"
```
The autogenerated header file will contain something similar to this:
```cpp
namespace <EnumName> {
enum Values {
Invalid = 0
Member_1_Name = 1;
Member_2_Name = 2;
...
};
}
```
Note that an `Invalid` member will be added automatically.
You can refer to the enum with `EnumName::Values` and to its values with `EnumName::Values::MemberName` or
`EnumName::MemberName`.
### Defining a struct
Structs can be defined like this
`<Name>.h` (the filename must match the name of the generated struct)
```cpp
#pragma once
// <copyright notice>
// Various includes (e.g. headers declaring field types)
#include "revng/ADT/Something.h"
/* TUPLE-TREE-YAML
name: <ClassName>
type: struct
doc: <Optional documentation about the struct itself>
fields:
- name: <Field1_name>
type: <Field1_type>
doc: <Optional documentation about this specific field>
- name: <Field2_name>
type: <Field2_type>
# marks a field as optional when deserializing YAML
optional: true
key:
# List the fields that uniquely identify an object inside a container here.
# They are also used for building the appropriate TupleTreeReference -- a "path" inside the YAML
- Index
TUPLE-TREE-YAML */
#include "revng/Model/Generated/Early/<Name>.h"
class model::<ClassName> : public model::generated::<ClassName> {
public:
// Inherit constructors from autogenerated class
using model::generated::<ClassName>::<ClassName>;
};
#include "revng/Model/Generated/Late/<Name>.h"
```
**Note**: You **must** define a class with a matching name that inherits from the generated class, between the `Early`
and the `Late` includes.
#### Sequence members
You can define a member composed of a sequence of items as follows
```yaml
name: MyStruct
type: struct
fields:
- name: MyArray
sequence:
type: std::vector
elementType: int
```
The sequence type must be instantiable with one type parameter (the element type). If the element type is polymorphic,
add `upcastable: true`
```yaml
name: MyStruct
type: struct
fields:
- name: MyArray
sequence:
type: std::vector
upcastable: true
elementType: efa::FunctionEdgeBase
```
This will get translated in C++ as `std::vector<UpcastablePointer<efa::FunctionEdgeBase>>`.
#### Reference members
Members can also specify references like this:
```yaml
name: MyStruct
type: struct
fields:
- name: MyRef
reference:
pointeeType: model::TypeDefinition
rootType: model::Binary
```
This gets translated in C++ as a `TupleTreeReference<model::TypeDefinition, model::Binary>`.
#### Upcastable structs
It is possible to define polymorphic classes. To do so, first define a common base class (like `Type`).
This class can be marked with the attribute `abstract` if it should not be instantiated on its own.
Example (`Type.h`):
```YAML
name: Type
type: struct
fields:
- name: Kind
type: model::TypeDefinitionKind::Values
...
key: [...]
abstract: true
```
Then, define the derived classes adding the `inherits: <ParentClass>` property (example from `StructDefinition.h`):
```YAML
name: StructDefinition
type: struct
inherits: Type
fields: [...]
```
Derived classes inherit the fields of their parent, so they must not be duplicated.