mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
cc57e57fd1
After this commit, every non-key field is treated as if it was optional while every key field (plus every auto-generated `Kind` field) - as if it was required.
218 lines
6.3 KiB
Markdown
218 lines
6.3 KiB
Markdown
## How to use `tuple_tree_generator`
|
|
|
|
`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.
|
|
|
|
**Note**: Never include the generated headers anywhere apart from the corresponding _hand-written_ header, which is the only file that should be included anywhere else (even in other headers generated from the same schema).
|
|
|
|
### Defining an enum
|
|
|
|
Enums can be defined by adding
|
|
```yaml
|
|
name: <Name>
|
|
type: enum
|
|
doc: <Documentation entry about the enum itself>
|
|
|
|
members:
|
|
- name: <Member_1_Name>
|
|
doc: <Documentation entry about the first enum member>
|
|
- name: <Member_2_Name>
|
|
doc: <Documentation entry about the second enum member>
|
|
```
|
|
to the corresponding schema (in this case `include/revng/Model/model-schema.yml`), and making a new header:
|
|
```cpp
|
|
#pragma once
|
|
|
|
// <copyright notice>
|
|
|
|
#include "revng/Model/Generated/Early/<Name>.h"
|
|
|
|
// <feel free to add other related definitions here>
|
|
|
|
#include "revng/Model/Generated/Late/<Name>.h"
|
|
```
|
|
|
|
**Note**: The header must be named `<Name>.h`, where `<Name>` is the same across the schema and the header internals (namely the `Early` and `Late` include statements).
|
|
|
|
|
|
The autogenerated header file will contain something similar to this:
|
|
|
|
```cpp
|
|
namespace <Name> {
|
|
enum Values {
|
|
Invalid = 0
|
|
Member_1_Name = 1;
|
|
Member_2_Name = 2;
|
|
// . . .
|
|
};
|
|
}
|
|
```
|
|
|
|
Note that an `Invalid` and `Count` members are **always** present, you don't need to add them manually.
|
|
|
|
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 by adding
|
|
```yaml
|
|
name: <Name>
|
|
type: struct
|
|
doc: <Documentation entry about the struct itself>
|
|
|
|
fields:
|
|
- name: <Field1_name>
|
|
type: <Field1_type>
|
|
doc: <Documentation entry about the first field>
|
|
- name: <Field2_name>
|
|
type: <Field2_type>
|
|
doc: <Documentation entry about the second field>
|
|
|
|
key:
|
|
# List the fields that uniquely identify an object inside a container here.
|
|
- Index
|
|
# These are also used for building the appropriate `TupleTreeReference` -- a "path" inside the tuple tree.
|
|
```
|
|
to the corresponding schema (in this case `include/revng/Model/model-schema.yml`), and making a new header:
|
|
```cpp
|
|
#pragma once
|
|
|
|
// <copyright notice>
|
|
|
|
// Include the dependencies of this new type here:
|
|
#include "revng/ADT/Something.h"
|
|
// Note that you can use *wrapper* headers generated from the same schema. Their order in the schema does *not* matter.
|
|
#include "revng/Model/<AnotherName>.h"
|
|
|
|
#include "revng/Model/Generated/Early/<Name>.h"
|
|
|
|
class model::<Name> : public model::generated::<Name> {
|
|
public:
|
|
// Note: don't forget to inherit constructors from autogenerated class
|
|
using model::generated::<ClassName>::<ClassName>;
|
|
|
|
// You can also add any extra methods you want here,
|
|
// but no fields are allowed - please use the scheme for those.
|
|
};
|
|
|
|
#include "revng/Model/Generated/Late/<Name>.h"
|
|
```
|
|
|
|
**Note**: The header must be named `<Name>.h`, where `<Name>` is the same across the schema and the header internals (namely the class name, as well as `Early` and `Late` include statements).
|
|
|
|
#### Sequence members
|
|
|
|
You can define a member composed of a sequence of items as follows
|
|
|
|
```yaml
|
|
name: MyStruct
|
|
type: struct
|
|
doc: Did you know `doc` is a required field everywhere it's available?
|
|
|
|
fields:
|
|
- name: MyArray
|
|
doc: |
|
|
Please don't use non-KOC containers in the model and other tuple trees
|
|
that take advantage of invalidation.
|
|
sequence:
|
|
type: SortedVector
|
|
elementType: int
|
|
```
|
|
|
|
The sequence type must be instantiable with one type parameter (the element type)! Which means you cannot currently use `std::pair` and friends.
|
|
|
|
Note that, if the specified `elementType` has `abstract: true` set in its *class* definition (see [here](#upcastable-structs) for more details), like here:
|
|
|
|
```yaml
|
|
name: MyStruct
|
|
type: struct
|
|
doc: Did you know `doc` is a required field everywhere it's available?
|
|
|
|
fields:
|
|
- name: MyArray
|
|
doc: |
|
|
Please don't use non-KOC containers in the model and other tuple trees
|
|
that take advantage of invalidation.
|
|
sequence:
|
|
type: SortedVector
|
|
elementType: MyAbstractType # <-- note the different type
|
|
```
|
|
|
|
the sequence will automatically be promoted to an upcastable pointer.
|
|
|
|
In this case:
|
|
```cpp
|
|
SortedVector<UpcastablePointer<MyAbstractType>>
|
|
```
|
|
|
|
#### Reference members
|
|
|
|
Members can also specify references like this:
|
|
|
|
```yaml
|
|
name: MyStruct
|
|
type: struct
|
|
doc: Did you know `doc` is a required field everywhere it's available?
|
|
|
|
fields:
|
|
- name: MyRef
|
|
doc: |
|
|
These references are polymorphic,
|
|
feel free to use abstract types, like here.
|
|
referenceTo: model::TypeDefinition
|
|
```
|
|
|
|
This gets translated in C++ as a
|
|
```cpp
|
|
TupleTreeReference<model::TypeDefinition, model::Binary>
|
|
```
|
|
where `model::Binary` is the root type of the `TupleTree` this struct is a part of.
|
|
|
|
#### Upcastable structs
|
|
|
|
It is possible to define polymorphic classes. To do so, first define a common base class (like `Type`).
|
|
This class has to be marked with the attribute `abstract`.
|
|
|
|
**Note**: this will mean that the class cannot be instantiated on its own. If that's desirable, please add an inheritor that doesn't add any extra fields to use instead.
|
|
|
|
Example (`TypeDefinition.h`):
|
|
|
|
```YAML
|
|
name: TypeDefinition
|
|
type: struct
|
|
|
|
abstract: true # <-- notice this
|
|
|
|
key:
|
|
- Kind
|
|
# . . .
|
|
|
|
fields:
|
|
- name: Kind
|
|
type: model::TypeDefinitionKind::Values
|
|
# . . .
|
|
```
|
|
|
|
Note that the `Kind` field is required! You will get a compilation time error if one is not present.
|
|
|
|
Also, the `<Name>Kind` enum is automatically added to the schema (so no need to do so manually).
|
|
**Note**: It's only added to the schema, you still have to make a header for it (see [how to define an enum](#defining-an-enum) for more details).
|
|
|
|
With the base out of the way, adding derived structs is as easy as making normal structs (see [here](#defining-a-struct)) with an extra `inherits: <ParentClass>` property.
|
|
|
|
For example:
|
|
```yaml
|
|
name: StructDefinition
|
|
type: struct
|
|
|
|
inherits: TypeDefinition # <-- notice this
|
|
|
|
fields:
|
|
# . . .
|
|
```
|
|
|
|
Note, that derived objects will contain all the fields of their parent, so the same names must not be used again.
|