07 July, 2009

Adding function to Xtext-generated plugins

The Xtext parser generator is generating much more than a parser—otherwise ANTLR by itself would be a simpler solution. As noted in my post on migrating the Xtext grammar, just by deploying the plugins generated by Xtext, a basic outline is provided while editing the defined language.

For my analyzer, I have to add checks that flag errors for programs that contain multiple definitions for certain types of structures. The legacy language allows a single name to be associated with multiple, different structure definitions as the program executes, but part of the upgrade will cause this to be illegal, so it's the job of the static analyzer (parser) to detect this case so the programmers don't have to search out and test each program manually.

The Xtext manual section on Validation includes Custom Validation describes the classes involved in implementing validations for the language. In order to get the Xtext customization framework for validation, add

<fragment class="org.eclipse.xtext.generator.validation.JavaValidatorFragment"/>
to the GenerateLanguageName.mwe file in the parser project. Unfortunately, the Java-based checks are not so easy to write as the oAW Check language. One of the nice things about oAW was the content assist—the editor for Check knows the AST model and makes it easy to write checks that work. There's another fragment to add to the MWE file in order to get the Check capability:
<fragment class="org.eclipse.xtext.generator.validation.CheckFragment"/>
Since the TMF Xtext plugins don't seem to include a Check editor with content assist, it's actually more convenient to write the validations in Java. Referring to the LanguageName.ecore file in the visual editor (should open when you double-click the ecore file) makes it pretty easy to see the types and their features when working on validations.

I just needed to add two validations (so far). The Java is pretty small, but it took me a little while to get comfortable with the CST classes.

/**
 * Issue warning if the View object is using the dynamic resolution syntax
 * @param view object to be validated
 */
@Check
public void checkViewNotDynamic(View view) {
  if (null != view.getDynamic())
    warning("View defined with dynamic target", PdlPackage.VIEW__DYNAMIC );
}
/**
 * Issue error if there there exist multiple Join objects identified by the same name
 * @param join one of the Join objects in the current ProcessDefinition 
 */
@Check
public void checkJoinUnique(final Join join) {
 final String name = join.getName(); // This name must not be used to identify any other Join object
  // Now loop on all the other elements that are in the ProcessDefintion
  for (EObject sibling : ((ProcessDefinition) join.eContainer()).getCommands()) {
    // Check for another object instance that's a Join with the same name as the one being validated
    if (join != sibling && sibling instanceof Join && name.equals(((Join) sibling).getName()))
      error("duplicate join '" + name + "'", PdlPackage.JOIN__NAME);
  }
}
These two validators are picked up by the Xtext framework and invoked by the editor and the generator. The warnings and errors show up in the editor as well as the Package Explorer, Problems and other views.

With the parser doing the right thing, I copied the Xpand template that I wrote under oAW into the generator project as templates/Template.xpt. The workflow/LanguageNameGenerator.mwe had a problem—it got a NoClassDefFoundError because it specified a class name in the register element with an initial lowercase letter. I don't know if that was because of something I did or a bug in the project wizard. Changing the MWE file was all that was needed to test the template. It's the same as oAW, which is to say it's a convenient way to traverse the CST and emit code.

«DEFINE main FOR ProcessDefinition»
  «FILE "test"»
    «EXPAND viewDef FOREACH commands.typeSelect(View)»
    «EXPAND joinDef FOREACH commands.typeSelect(Join)»
  «ENDFILE»
«ENDDEFINE»

//In the output file, there will be one line for each instance of Join
//Within the tempate, the properties of the instance are accessed like
//local variables.
«DEFINE joinDef FOR Join »
// Pay no attention to the man behind the curtain named «name»
«ENDDEFINE»

«DEFINE viewDef FOR View »
 «IF null!=name && null!=source -» «REM» Generate mappings for statically-defined views «ENDREM»
 views["«name.toUpperCase()»"] = joins.createView("«source.toUpperCase()»");
 «ENDIF -»
«ENDDEFINE»
You'll notice that the template language uses guillemets to enclose the executable instructions. To make sure that you read all of the documentation, the authors only tell you that the characters are bound to CTRL-< and CTRL-> at the end. The Xpand editor was pretty nice to use in oAW. I haven't tried it yet in TMF, partly because it wasn't installed. I'm not quite sure how I got the runtime plugin for Xpand installed—perhaps p2 resolved a dependency. I'm pretty sure that once I install the Xpand UI from the M2T Xpand update site, I'll get the content assist that I used when I was originally developing the template.

5 comments:

  1. Is there a way to add Java parser into Xtext?
    Part of my DSL is written in Java, and I need Xtext editor to give me all those nice editing features. any hints?

    ReplyDelete
  2. Though I'm not entirely sure that you mean that your DSL grammar includes Java syntax, the literal answer to the question "Is it possible?" would be 'yes'. It's a bit strange to say that a DSL _includes_ Java grammar as that would imply the language isn't very specific.

    You can probably take an Antlr grammar for Java and rework into an Xtext grammar without too much work. The Xtext team had some work planned for boilerplate grammars, but I don't know what's available today.

    I'm certainly curious about your undertaking, so thanks for posting the comment!

    ReplyDelete
  3. Thanks John for your reply. To clarify, my language supports some constructs where you can add any native language. so for example, A state machine entry action is implemented as follows:

    state ON {
    entry / { **Java code here** }
    }

    I was hoping to be able to reuse an existing Xtext grammar for Java, without having to rewrite one myself.

    And you are right, the language is not very specific. If you are interested, you can read more about the language here: http://cruise.site.uottawa.ca/umpleonline/

    ReplyDelete

 

Copyright 2009-2010 John Bito. Creative Commons License
This work is licensed under a Creative Commons Attribution-NoDerivs 3.0 Unported License.