Files
2022-04-20 11:25:46 +02:00
..
2022-04-12 16:40:27 +02:00
2022-04-15 18:25:11 +02:00
2022-03-08 13:06:49 +01:00
2022-04-05 15:37:57 +02:00
2022-02-14 09:39:44 +01:00
2022-03-08 15:04:34 +01:00
2022-03-08 15:04:29 +01:00
2022-03-08 12:25:59 +01:00
2022-03-08 12:26:07 +01:00
2022-03-08 13:06:47 +01:00
2022-04-15 15:15:41 +02:00
2022-04-08 18:58:58 +02:00

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 KeyedObjectContainers, 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)

#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:

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)

#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

name: MyStruct
type: struct
fileds:
  - 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

name: MyStruct
type: struct
fileds:
  - 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:

name: MyStruct
type: struct
fileds:
  - name: MyRef
    reference:
      pointeeType: model::Type
      rootType: model::Binary

This gets translated in C++ as a TupleTreeReference<model::Type, 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):

name: Type
type: struct
fields:
  - name: Kind
    type: model::TypeKind::Values
  ...
key: [...]
abstract: true

Then, define the derived classes adding the inherits: <ParentClass> property (example from StructType.h):

name: StructType
type: struct
inherits: Type
fields: [...]

Derived classes inherit the fields of their parent, so they must not be duplicated.

All classes that are part of a polymorphic hierarchy are expected to supply two classof methods:

// Don't inherit from model::Type or model::generated::Type!
class model::StructType : public model::generated::StructType {
public:
  using model::generated::StructType::StructType;

  // ...

public:
  static bool classof(const Type *T) { return classof(T->key()); }
  static bool classof(const Key &K) { return std::get<0>(K) == AssociatedKind; }
};

The classof methods should return true if the object they receive (an instance of the polymorphic object or of the object key) can be identified as an object of the current class.