-
Notifications
You must be signed in to change notification settings - Fork 4
Writing a Generator
Before you can write a generator you need to know the capabilities of the target language you want to support. * Does it support structured data types?
- Does it support object-oriented programming?
- Does it support arrays or lists?
- Does is support constants or is there a pattern how to realize constants?
When you add a new generator, first create a package for your generator in the generator package. For example, you want to write a generator for C#, you would create a package de.cau.cs.instrumentation.rl.generator.csharp
. In that directory you create two classes (preferably Xtend classes) named RecordTypeGenerator
and TemplateTypeGenerator
. They must be derived from AbstractRecordTypeGenerator
and AbstractTemplateTypeGenerator
and implement the common interface. In Eclipse the editor will ask you to add all the unimplemented methods which are enforced by the abstract classes. In Xtend and Java the editor will provide a quick fix to add the necessary code. These methods must be initialized with the correct values. See the following listing for a descriptive example.
class RecordTypeGenerator extends AbstractRecordTypeGenerator {
/**
* Return the unique language id for this generator.
*/
override getId() '''csharp'''
/**
* Return the preferences activation description.
*/
override getDescription() '''C# record generator'''
/**
* Define language/generation type, which is also used to define the outlet.
* The outlet defines which outlet configuration is later used to write results.
* While the id defines to which language this generator belongs to.
*/
override getOutletType() '''csharp'''
/**
* Compute the directory name for a record type. This example creates nested
* folders for the nested package structure.
*/
override getDirectoryName(Type type) '''«(type.eContainer as Model).name.replace('.',File::separator)»'''
/**
* Compute file name.
*/
override getFileName(Type type) '''«type.getDirectoryName»«File::separator»«type.name».cs'''
/**
* Depending on the target language, this must be true or false. If
* abstract record types should be generated set it to true else false.
*/
override supportsAbstractRecordType() { true }
/**
* Primary code generation template.
*
* @param type
* one record type to be used to create monitoring record
* @param author
* generic author name for the record
* @param version
* generic kieker version for the record
*/
override createContent(RecordType type, String author, String version) {
}
}
Templates look quite similar, however, they lack a number of methods. The core of both generators is the createContent
method. The parameters author
and version
are provided to the generator as default values for these two properties of a record if the annotations for author and since are missing. The record and template type is the first parameter.
Finally, you have to register you generators. Therefore, open the de.cau.cs.se.instrumentation.rl.generator.GeneratorConfiguration
and add your generator to the RECORD_TYPE_GENERATORS
and TEMPLATE_TYPE_GENERATORS
arrays. Then define an outlet for your language. It is not necessary to create a new outlet for every generator when they will share a directory. However, we recommend to create one. In our example, this would be new OutletConfiguration("csharp", "C# Output Folder", "./srg-gen/csharp")
.
If your language supports interfaces and classes then you should realize the type mapping in an external extension class in Xtend. Create a class ModelTypeToCSharpTypeExtensions
in the same package as the two generator classes. The class must inherit the IModelTypetoTargetTypeExtensions
interface.
interface IModelTypeToTargetTypeExtensions {
/**
* Determine the right primitive target type string for a given system type.
*
* @param classifier
* A type name of the record language
* @return
* the target type name of the given <code>classifier</code>
*/
def String createPrimitiveTypeName(EClassifier classifier)
/**
* Determine the right target type class string for a given system type.
*/
def String createPrimitiveWrapperTypeName(EClassifier classifier)
}
The first function returns the correct primitive target type for a specific source type and the second is used for boxing types. If your target language has no corresponding boxing types, then the second method can stay unimplemented. Please add a corresponding throw new UnsupportedOperationException()
in the method body with a proper message.
Note: In future, the type mapping interface will be improved and return the correct target type for a given source type including arrays and imported properties.
We encourage to first create an example with most features used in your language and then use that example as starting template in the createContent
method. You may consult the other languages generators for more detail.
For the collection of properties and other utility functions regarding the source model, have a look at de.cau.cs.se.instrumentation.rl.validation.PropertyEvaluation
.