A single keyword often has multiple effects, and so needs multiple
transformation methods. Add another method to the Property class, with the
following skeleton:
satisfies<methodDefinition>
public void addAccessors(FieldNode target)
{
}
We want this method to generate new accessor methods for the field it is given. To do so, first
we will need to get a representation of the class in which the field was defined, like so:
ClassNode targetClass = target.getDeclaringClass();
Next we will use the extend() method of ClassNode. This allows new members to be added to the class
simply by specifying their source code. extend() takes a simple String, but we will create the String
using a special string literal syntax introduced in ELIDE: instead of quotes, strings are enclosed between
%{ and }%. These strings have three special properties:
- they can span multiple lines
- special characters such as " do not need to be escaped
- they can leave "holes" for variables or expressions using #{ }# to mark off code.
For example,
String text = %{ this is "test" number #{x + 5}#! }%;
is equivalent to
String text = " this is \"test\" number " + (x + 5) + "!";
Add the following code to your class:
String name = target.getName();
String type = target.getType();
String upperCaseName = Utils.methodCase(name);
targetClass.extend(%{
public #{type}# get#{upperCaseName}#()
{
return #{name}#;
}
public void set#{upperCaseName}# (#{type}# #{name}#)
{
this.#{name}# = #{name}#;
}
}%);
This adds getter and setter methods to the target class, leaving three
holes to be filled in by the name or type of the target instance variable.
The Utils class provides a number of convenience methods such as methodCase (which capitalizes
the first letter of a string) - for a full reference, see the Transformation Definition Reference
Your class should currently look like this:
package tutorial;
import ca.ubc.cs.elide.*;
import ca.ubc.cs.elide.nodes.*;
public class Property extends Transform
{
satisfies<fieldAccess>
public void makeFieldPrivate(FieldNode target)
{
target.makePrivate();
}
satisfies<methodDefinition>
public void addAccessors(FieldNode target)
{
ClassNode targetClass = target.getDeclaringClass();
String name = target.getName();
String type = target.getType();
String upperCaseName = Utils.methodCase(name);
targetClass.extend(%{
public #{type}# get#{upperCaseName}#()
{
return #{name}#;
}
public void set#{upperCaseName}# (#{type}# #{name}#)
{
this.#{name}# = #{name}#;
}
}%);
}
}
And if you now run ELIDE, you should get the following in output/ElideTest.java:
public class ElideTest extends Object
{
private int x;
private String[] y;
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
public String[] getY()
{
return y;
}
public void setY(String[] y)
{
this.y = y;
}
}