In DWARF, `STT_GNU_IFUNC` symbols are associated to a function prototype returning the actual prototype.
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 KeyedObjectContainers, 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
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:
#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:
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
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:
#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
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 for more details), like here:
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:
SortedVector<UpcastablePointer<MyAbstractType>>
Reference members
Members can also specify references like this:
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
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):
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 for more details).
With the base out of the way, adding derived structs is as easy as making normal structs (see here) with an extra inherits: <ParentClass> property.
For example:
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.