mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
178 lines
4.3 KiB
Markdown
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.
|