Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Papyrus-RT/Developer/Design/0.8/Codegen Extension

< Papyrus-RT‎ | Developer‎ | Design
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
PapyrusForRealTime-Logo-Icon.png


Extending the Code Generator


Introduction

The PapyrusRT code generator can be extended using the Eclipse plugin extension mechanism. The org.eclipse.papyrusrt.codegen.cpp plugin defines an extension point called generator to provide generator classes. A plugin for a custom generator needs to define an extension linked to this generator extension point, and specify a custom generator class implementing this extension. The custom generator must be a subclass of AbstractCppGenerator, defined in the same org.eclipse.papyrusrt.codegen.cpp plugin.

In the definition of the extension, the type must be one of the following:

  • ClassGenerator
  • CapsuleGenerator
  • ProtocolGenerator
  • StateMachineGenerator
  • StructureGenerator

The class associated to the extension must implement the AbstractCppGenerator.Factory interface, which is used by the generator to create instances of each specific generator.


The following example describes the usual steps required to create a custom generator and provide the extension.

This assumes that you have installed a PapyrusRT development environment as described in Mars Development Environment.

Create a Plug-in Project

  1. Go to File → New → Other... → Plug-in Project
  2. Enter the name of the project and all relevant fields. In this example we will use the name "myproject.mygen"
Note.png
In the "Content" dialog, uncheck the "Generate an activator" and the "This plug-in will make contributions to the UI" options.


Configure the new plug-in dependencies

The new plug-in needs at least the following three plug-ins:

  • org.eclipse.papyrusrt.codegen.cpp: the code generator which provides the base generators and extension point.
  • org.eclipse.papyrusrt.codegen.xtumlrt.common.model: the meta-model of the intermediate representation (xtUMLrt)
  • org.eclipse.papyrusrt.codegen.lang.cpp: the meta-model of the target C++ subset.
  1. If not already open, open the new project's META-INF/MANIFEST.MF file.
    Genext-1-new-plugin-proj-v2.png
  2. Click on the "Dependencies" tab.
    Genext-2-dep-tab-v2.png
  3. Click the [Add...] button, search for org.eclipse.papyrusrt.codegen.cpp, select it and click [OK].
    Genext-3-add-dep-v2.png
  4. Click the [Add...] button, search for org.eclipse.papyrusrt.codegen.xtumlrt.common.model, select it and click [OK].
  5. Click the [Add...] button, search for org.eclipse.papyrusrt.codegen.lang.cpp, select it and click [OK].
    Genext-4-deps-added-v2.png
  6. Save.

Note: you may add other dependencies that you need.

Create a generator class

In the Project Explorer navigate to the plug-in's source folder (usually called "src") and create a new class there. The new class must be a subclass of org.eclipse.papyrusrt.codegen.cpp.AbstractCppGenerator.

Note.png
You may extend the built-in generators found in org.eclipse.papyrusrt.codegen.cpp.internal, but beware that they are not part of the official API and their interface is subject to change. These generators are:
  • ArtifactGenerator
  • BasicClassGenerator
  • EnumGenerator
  • CapsuleGenerator
  • SerializableClassGenerator
  • ProtocolGenerator
  • StateMachineGenerator
  • CompositionGenerator


In this example we are going to extend the BasicClassGenerator. After creating the class, its source code should look like this:

package myproject.mygen;

import org.eclipse.papyrusrt.codegen.cpp.CppCodePattern;
import org.eclipse.papyrusrt.codegen.cpp.internal.BasicClassGenerator;
import org.eclipse.papyrusrt.xtumlrt.common.Type;

public class MyClassGenerator extends BasicClassGenerator {

	public MyClassGenerator(CppCodePattern cpp, Type element) {
		super(cpp, element);
		// TODO Auto-generated constructor stub
	}

}

The generator needs to provide a factory class which the PapyrusRT code generator manager (GeneratorManager and EclipseGeneratorManager) will use to obtain instances of your generator. This factory must implement the AbstractCppGenerator.Factory interface. The most natural location for this is within your own generator class:

package myproject.mygen;

import org.eclipse.papyrusrt.codegen.cpp.AbstractCppGenerator;
import org.eclipse.papyrusrt.codegen.cpp.CppCodePattern;
import org.eclipse.papyrusrt.codegen.cpp.internal.BasicClassGenerator;
import org.eclipse.papyrusrt.xtumlrt.common.StructuredType;
import org.eclipse.papyrusrt.xtumlrt.common.Package;

public class MyClassGenerator extends BasicClassGenerator {

    private StructuredType element;
    private Package context;
	
    public MyClassGenerator( CppCodePattern cpp, StructuredType element, Package context ) {
        super(cpp, element);
        this.element = element;
        this.context = context;
    }

    public static class Factory implements AbstractCppGenerator.Factory<StructuredType, Package>
    {
        @Override
        public AbstractCppGenerator create( CppCodePattern cpp, StructuredType element, Package context )
        {
            return new MyClassGenerator( cpp, element, context );
        }
    }

    @Override
    public boolean generate() {
    	// The actual generation goes here.
    	// This method uses this.element and may use this.context
    	return false;
    }
    
}

Several things to notice in this example. First, we added two fields, element and context of types StructuredType and Package.

The element field will be assigned the source element from the intermediate representation (an xtUMLrt element). This is, the element for which we are generating code. In our example, the element will be a class, and classes are represented in xtUMLrt by StructuredType objects.

The context field will be assigned the appropriate context element. This depends on the particular element that we are interested in. For classes, the context is the (xtUMLrt) Package in which the StructuredType is defined. A custom code generator may use this or may choose to ignore it.

We also updated the constructor to assign the element and context fields.

We added an inner static class called Factory, which implements the AbstractCppGenerator.Factory interface. This class provides a factory method to create instances of the custom generator when the full generator is executed. The interface is a template, parametrized by the types of the element and context. The factory method is called create, returns an instance of the custom generator, and expects three arguments:

  1. CppCodePattern cpp: the core interface to the C++ meta-model and the specific code patterns produced in that meta-model (see Papyrus-RT/Developer Guide/Codegen Details)
  2. StructuredType element: the (xtUMLrt) element to be generated
  3. Package context: the (xtUMLrt) context of the element

In our case, this factory method is quite simple. It just invokes the constructor.

Finally, we override the generate method from AbstractCppGenerator to provide our own logic. This method returns a boolean indicating the success or failure of the generation.

When extending the built-in generators, we can override other methods.

The generate will use the cpp instance, as well as any classes in the org.eclipse.papyrusrt.codegen.lang.cpp package to create C++ elements. There is no need to explicitly generate text here. The cpp instance will record all C++ elements created and after generate has finished, the main generator will invoke cpp.write to transform the C++ model into source C++ text files.

For example, we can make our custom generator create a C++ class with a single method called run as follows:

    @Override
    public boolean generate() {
        CppClass cls = cpp.getWritableCppClass( CppCodePattern.Output.BasicClass, element );
        MemberFunction function = new MemberFunction( PrimitiveType.VOID, "run" );
        function.add( new UserCode( "for (int i = 0; i < 100; i++) ;" ));
        cls.addMember( Visibility.PUBLIC, function );
        return true;
    }

The first line creates a C++ class for the given element. The second creates a member function called "run", with return type "void" and no parameters. The third line adds a statement. In this case it is some fixed user code. The fourth line adds this function to the class created in the first line, with public visibility.

Define the generator extension

Finally, we need to hook up our generator to the generator extension point provided by org.eclipse.papyrusrt.codegen.cpp.

  1. Open the plugin's META-INF/MANIFEST.MF file, and go to the "Extensions" tab:
    Genext-5-ext-tab-v2.png
  2. Click [Add...] and search for the generator extension point from the org.eclipse.papyrusrt.codegen.cpp plugin:
    Genext-6-find-generator-v2.png
    After clicking [OK] it looks like this:
    Genext-7-generator-found-v2.png
  3. Set the type to ClassGenerator, the class to myproject.mygen.MyClassGenerator$Factory, and the priority to High
    Genext-8-set-type-class-v2.png

Done!

And it's done! When you execute PapyrusRT with your custom plugin, this generator will override the default generator for basic classes.

For other generator types, the type of the extension should be set accordingly. The types supported are the following:

  • ArtifactGenerator (for subclasses of ArtifactGenerator)
  • BehaviourGenerator (for subclasses of BehaviourGenerator (not yet implemented))
  • ClassGenerator (for subclasses of BasicClassGenerator)
  • CapsuleGenerator (for subclasses of CapsuleGenerator)
  • EnumGenerator (for subclasses of EnumGenerator)
  • ProtocolGenerator (for subclasses of ProtocolGenerator)
  • SerializableClassGenerator (for subclasses of SerializableClassGenerator)
  • StateMachineGenerator (for subclasses of StateMachineGenerator)
  • StructureGenerator (for subclasses of CompositionGenerator)

Back to the top