...
- Add a new plug-in project
de.cau.cs.rtprak.login.compiler
to your workspace. Be sure to uncheck the option This plug-in will make contributions to the UI. Add dependencies to the two projects containing the Turing Machine metamodel and the programming language metamodel. - Add an Xtend Class to your project. The class should be placed in a subpackage where all the transformation code will go, such as
de.cau.cs.rtprak.login.compiler.transform
. - You will notice that your new class is marked with an error marker because of a missing dependency of the new plug-in project to
org.eclipse.xtext.xbase.lib
. If you hover over the error with your mouse, you can have Eclipse add all libraries required by Xtend to your project. Define an entry method for the transformation that takes a
TuringMachine
instance as an argument and returns aProgram
. You can use the following definition as a starting point:Code Block language java /** * Transforms a given Turing Machine into an imperative program model. * * @param machine the Turing Machine to transform into an imperative * program. * @return a program model that implements the Turing Machine. */ def Program transformTuringToImperative(TuringMachine machine) { // Create the program we will transform the Turing Machine into val program = ImperativeFactory::eINSTANCE.createProgram() // TODO: Initialize program appropriately // TODO: Call methods that generate the Program model // Return the transformed program program }
There's a few points to note here:
- Lines in Xtend code don't have to and with a semicolon.
- We have been explicit about the method's return type, but we could have easily omitted it, letting Xtend infer the return type.
- The keyword
val
declares a constant, whilevar
declares a variable. Try to make do with constants where possible. - The methods you call should be declared as
def private
since they are implementation details and shouldn't be called by other classes. - You may be tempted to add a few global variables that hold things like a global input variable or a pointer to the current state. While you could to that,
def create
methods might offer a better alternative...
- Add code to transform the Turing Machine to an imperative program model. The imperative program metamodel contains enough stuff to implement Turing Machines.
- Open the Plug-In Manifest Editor and switch to the Runtime tab. Add the package containing your transformation to the list of exported packages. (You may have to check the Show non-Java packages option in the Exported Packages dialog to see the package.)
Testing the Transformation
You will need a way to test the transformation, so we will have to make it available through the UI. Eclipse plug-ins often come with a separate UI plug-in that contains the UI contributions, with the base plug-in only offering the functionality itself. In our case, our base plug-in contains the transformation code, and the UI plug-in we will be creating next contains a menu contribution to make the transformation available.
- Add a new plug-in project
de.cau.cs.rtprak.login.compiler.ui
to your workspace. This time, leave the option This plug-in will make contributions to the UI checked. Add dependencies to the two projects containing the Turing Machine metamodel and the programming language metamodel. Also add a dependency to our base plug-in that contains the transformation. - Add a menu contribution that is visible if a file containing a Turing Machine model is selected in the project explorer. The previous tutorial taught you how to add menu contributions.
Create a command handler that loads the turing machine model from the selected file, calls the transformation on the model, and saves the imperative program to a file with the same name, but different extension. You can use the following code as a template: (The code requires a dependency to
com.google.inject
to work.)Code Block language java @Override public Object execute(ExecutionEvent event) throws ExecutionException { ISelection selection = HandlerUtil.getCurrentSelection(event); if (selection instanceof IStructuredSelection) { Object element = ((IStructuredSelection) selection).getFirstElement(); if (element instanceof IFile) { IFile machineFile = (IFile) element; // Load Turing Machine TuringMachine machine = loadTuringMachine(machineFile); // Call the transformation Injector injector = Guice.createInjector(); TuringToImperativeTransformation transformation = injector.getInstance(TuringToImperativeTransformation.class); Program program = transformation.transformTuringToImperative(machine); // Save imperative program IPath programFilePath = machineFile.getParent().getFullPath().append( machineFile.getName() + ".imperative"); IFile programFile = machineFile.getParent().getFile(programFilePath); saveImperativeProgram(programFile, program); } } return null; } /** * Load the turing machine model from the given file. * * @param turingFile the file to load the turing machine model from. * @return the turing machine model. * @throws ExecutionException if the file couldn't be opened. */ private TuringMachine loadTuringMachine(IFile turingFile) throws ExecutionException { // TODO Implement. } /** * Saves the given imperative program in the given file. * * @param programFile the file to save the program to. * @param program the program to save. * @throws ExecutionException if there was an error saving the file. */ private void saveImperativeProgram(IFile programFile, Program program) throws ExecutionException { // TODO Implement }
Code Generation
TODO: Write this section.
...