Personalities/J Compiler
Project Description

ATTENTION: For the latest information about Personalities and the Personalities/J compiler definition, please consult Chapter 4 of the Personalities Thesis For a complete example of both static and dynamic personalities please download: PJ Example


Introduction

Personalities/J is an extension to the Java language to allow for a more flexible way of designing software systems based on roles. Java is extended to support a new entity, a personality, which resembles an interface but contains the implementation of certain functions and imposes a number of semantic constraints both on its usage and its implementation. For much more information about personalities, please see this page.

The Personalities/J Compiler

The purpose of the compiler is to take a set of .pj files and turn them into .wvr (Weaver) files. The Weaver module is part of the Demeter/Java system and is used to easily implement the code-generation phase of the compiler. Alternatively, a student might elect not to use the weaver in which case the Personalities/J compiler will output standard Java code. For more information about the weaver tool see

http://www.ccs.neu.edu/home/jayantha/usermanual/node6.html.
 

Figure 1 shows the two potential architectures of the Personalities/J compiler.

Figure 1: Two architectures of the Personalities/J compiler (pjc)

 

Implementation Details

To implement the compiler, we suggest using Demeter/Java’s extensive parsing and traversal facilities. To illustrate in more detail what the compiler is supposed to do, we will reproduce parts of the paper mentioned above.

Details about Personalities

Defining a personality is similar to defining a class, with a few added keywords. For example, the Flier personality can be defined as follows (new keywords are underlined):

// Flier.pj
personality Flier {
    // upstream interface. Must implement here.
    public
    void Fly(int miles, int altitude) {
        Takeoff();
        for (int a=0; a < altitude; a++) Ascend();
        while(miles--) Flap();
        for(a = altitude; a > 0; a--) Descend();
        Land();
    }

    // downstream interface. Don’t impl here.
    di void Takeoff();
    di void Ascend();
    di void Flap();
    di void Descend();
    di void Land();
    private some_other_function() {...}
}

A personality definition consists of three basic elements: When a class decides to personify a given personality, it needs to declare its intent (via the personifies clause), as well as provide the methods specified in the downstream interface. For example, a (trivial) definition of the Mosquito class could be: public class Mosquito extends Insect
                      personifies Flier
{
    int height = 0;
    public Mosquito() {}
    private boolean stingingSomebody() {...}
    private void jumpInTheAirAndStartFlapping() {}
    // downstream interface implementation
    public void Takeoff() {
        while ( stingingSomebody() ) {
            // wait for some time
        }
        jumpInTheAirAndStartFlapping();
    }
    public void Ascend() {...}
    public void Flap() {...}
    public void Descend() {...}
    public void Land() {...}
}
Continuing with the example, the definition of the Walker personality follows: //Walker.pj
personality Walker
{
    public void Walk(int distance) {
        Prepare();
        while( distance-- ) {
            for(int f=0; f < NumberOfFeet(); f++)
                MoveFoot(f);
            Stabilize();
        }
        AtEase();
    }
    di void Prepare(); // downstream
    di int NumberOfFeet(); // interface
    di void MoveFoot(int);
    di void Stabilize();
    di void AtEase();
}
The definition of the Locust class follows: // Locust.pj
public class Locust extends Insect
                    personifies Walker, Flier
{
    // ... details about Locust class ...
    // as required by Walker.pj
    void Prepare() { ... }
    int NumberOfFeet() { ... }
    void MoveFoot(int no) { ... }
    void Stabilize() { ... }
    void AtEase() { ... }
    // as required by Flier.pj
    void Takeoff() { ... }
    void Ascend() { ... }
    void Flap() { ... }
    void Descend() { ... }
    void Land() { ... }
}
The Personalities/J compiler will generate:
  1. the interfaces Walker.java and Flier.java which lay down the signatures for both the upstream and downstream interfaces of the Walker and Flier personalities, respectively
  2. the Walker$Ego.java and Flier$Ego.java classes which contain the implementations of the upstream behavior of Walker and Flier personalities, respectively, and
  3. the class Locust.java for the concrete animal class that personifies both a Flier and a Walker.
Sample generated code is shown below: // Walker.java
interface Walker {
    void Walk(int distance);
    void Prepare();
    int NumberOfFeet();
    void MoveFoot(int feetno);
    void Stabilize();
    void AtEase();
}
// Flier.java
interface Flier {
    void Fly(int miles, int altitude);
    void Takeoff();
    void Ascend();
    void Flap();
    void Descend();
    void Land();
}
// Locust.java
public class Locust extends Insect
                    implements Walker, Flier
{
    // ... details about Locust class ...
    // as required by Walker.pj
    void Prepare() { ... }
    int NumberOfFeet() { ... }
    void MoveFoot(int no) { ... }
    void Stabilize() { ... }
    void AtEase() { ... }
    // as required by Flier.pj
    void Takeoff() { ... }
    void Ascend() { ... }
    void Flap() { ... }
    void Descend() { ... }
    void Land() { ... }
    // compiler-generated code
    Walker$Ego $walker = new Walker$Ego();
    public void Walk(int distance)
    { $walker.Walk(this, distance); }
    Flier$Ego $flier = new Flier$Ego();
    public void Fly(int miles, int altitude)
    { $flier.Fly(this, miles, altitude); }
}
// Walker$Ego.java
public class Walker$Ego
{
    public void Walk(Walker host, int distance) {
        host.Prepare();
        while( (distance--) > 0 ) {
            for (int f=0; f<host.NumberOfFeet(); f++)
                host.MoveFoot(f);
            host.Stabilize();
        }
        host.AtEase();
    }
}
// Flier$Ego.java
class Flier$Ego
{
    public void Fly(Flier host, int miles,
                    int altitude) {
        host.Takeoff();
        for (int a = 0; a < altitude; a++)
            host.Ascend();
        while((miles--) > 0) host.Flap();
        for(int a = altitude; a > 0; a--)
            host.Descend();
        host.Land();
    }
}
 
A Hand-Compiled Example

To better understand the input passed to the compiler, as well as its ultimate output, we have provided a hand-compiled example. You can test your compiler against these files to make sure it works. Download the example.zip file here.

Work in Progress

Research in Personalities is evolving. Some of the things we are thinking about include:

Thus, the Personalities/J compiler definition might change in the future. Suggestions, ideas, and criticism are welcome and expected.

 

How to Get Help

Please email me at: lblando@alum.mit.edu