Friday, April 6, 2012

Tackling Reverse Code Generation

Reverse Code Generation has been kindly discussed in depth by my friend Daniel Dietrich.

To review, the goal is to make it possible to generate 2 artifacts (generator templates and generated application) from 2 artifacts (model and prototype application).

Given this pseudo-Java prototype application:

public void runHello(String[] args) {
  System.out.println("Welcome to Hello World!");
}

And this model:

appName "Hello"
appTitle "Hello World"

I'd like to generate (or perhaps, "reverse generate") this generator template (in StringTemplate syntax):

public void run$appName$(String[] args) {
  System.out.println("Welcome to $appTitle$!");
}

You can think of the above as a representation of the "template" model too. (template is data therefore template is a model, right?)

Now given the actual application model :

appName "Car"
appTitle "Ultimate Car Selling"

This model plus the generated generator template would ultimately generate the final application :

public void runCar(String[] args) {
  System.out.println("Welcome to Ultimate Car Selling!");
}


Is it Worth It?

My first question even if all this is possible and practical, is it worth all the hassle?

My hunch tells me that right now, at best it's seldom used and at worst exotic.

And then about limitations. It's like projecting 3D onto 2D and then trying to get 3D back out of that 2D. It's not just challenging, but some information is lost.

These information can be recorded somewhere (like metadata for generated code), however if we used features like protected regions it'll make it even more challenging. (some heuristics would help though)

Then about loops and conditionals.

The Solution?

The way I think about it right now is that reverse code generation would be like a submodule inside a greater code generation task. Kinda like protected regions. So the reverse generator does not work globally, but only in specific parts of the project. And for those parts, we know that there are no loops or conditionals or complex constructs. UPCASE and down_case transformations etc. may still be practical.

The key lies in the prototype application. The prototype needs to serve a double role:
  1. It is directly executable/buildable as a project in the target platform environment
  2. It can be extracted to form generator templates

So we have to annotate the prototype app in some way. The annotations can be external (like Hibernate/JPA Persistence XML mappings) or internal (like JPA Java annotations, JAX-RS, etc.).

For internal annotations, there seems to be no other way than using the comment capability in the target language, just like protected regions. If the target language doesn't support comments, then the only possible approach is external annotations.

Simple syntax out of my mind:

/** GENERATOR: START
public void run$appName$(String[] args) {
  System.out.println("Welcome to $appTitle$!");
}
*/
public void runHello(String[] args) {
  System.out.println("Welcome to Hello World!");
}
//
GENERATOR: END

Basically we write the offending code twice, one as a template and one in the target language. It seems useless for that example but consider another example:

<?xml version="1.0" encoding="utf-8"?>
<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.1">
<!-- GENERATOR START
  <App xmlns="" ProductID="$productId$" Title="$appTitle$"
       RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal"  Author="$appAuthor$"

       Description="$appDescription$" Publisher="$appPublisher$">
-->
  <App xmlns="" ProductID="{6b7a1ae6-8d4e-4f85-b08e-387df81d6e8e}" Title="Info Bandung"
       RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal"  Author="Hendy Irawan"

       Description="Woyyy, Orang Bandung kita bagi2 Info" Publisher="Hendy Irawan">
<!-- GENERATOR END -->
    <IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
    <Capabilities>
      <Capability Name="ID_CAP_NETWORKING"/>
    </Capabilities>
    <Tasks>
      <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml"/>
    </Tasks>
    <Tokens>
<!-- GENERATOR SINGLE
      <PrimaryToken TokenID="$appName$Token" TaskName="_default">
-->
      <PrimaryToken TokenID="InfoBandungToken" TaskName="_default">
        <TemplateType5>
          <BackgroundImageURI IsRelative="true" IsResource="false">Background.png</BackgroundImageURI>
          <Count>0</Count>
<!-- GENERATOR SINGLE
          <Title>$appTitle</Title>
-->
          <Title>Info Bandung</Title>
        </TemplateType5>
      </PrimaryToken>
    </Tokens>
  </App>
</Deployment>

Doesn't look too bad, does it? And I can foresee writing the reverse code generator for that is doable.

And the above code (not the reverse code generator though) isn't entirely imaginary. I have taken it out directly from my open source Windows Phone 7 project Info Bandung.

What do you think?


To learn Modeling with Eclipse Modeling Framework (EMF), I highly recommend the book EMF: Eclipse Modeling Framework.