Menu

Methods

Donald Strong

[Home]


Language Features

Methods

Declaring methods

Methods are declared in !ClassMaker using the following methods.

    public void Method(String methodName, Class returnType, int methodModifiers) throws ClassMakerException
    public void Method(String methodName, Type returnType, int methodModifiers) throws ClassMakerException
    public void Begin() throws ClassMakerException
    public void End() throws ClassMakerException

There are two versions of Method and Declare.
Most of the time you will use the version that takes a java reflection Class.
The version that takes a !ClassMaker Type is only necessary when you are passing a class
that you are generating at runtime.

Java codeClassMaker code
 
    String name;
           
    public void exec()
    {
        name = "Hello World";
    }
 
    Declare("name", String.class, ACC_PUBLIC);
 
    Method("exec", void.class, ACC_PUBLIC);
    Begin();
        Eval(Set(This(), "name", Literal("Hello World")));
    End();

Valid bitmasks for the methodModifiers of a Method call include ACC_PUBLIC,
ACC_PROTECTED or ACC_PRIVATE. The modifiers may be bitwise ORed with
ACC_STATIC and ACC_FINAL, as appropriate.
Provide a zero (0) value if there are no modifiers.

Formal Parameters

Formal parameters are declared in ClassMaker using the following methods.

    public void Declare(String name, Class javaClass, int modifiers) throws ClassMakerException
    public void Declare(String name, String typeName, int modifiers) throws ClassMakerException
    public void Declare(String name, Type type, int modifiers) throws ClassMakerException
Java codeClassMaker code
 
    public void setName(String name)
    {
        this.name = name;
    }
 
    Method("setName", void.class, ACC_PUBLIC);
    Declare("name", String.class, 0);
    Begin();
        Eval(Set(This(), "name", Get("name")));
    End();

The only valid values for the modifiers of a Declare call when used to declare a
formal parameter are ACC_FINAL or zero (0).

Returning values

These methods are used in ClassMaker to return from a method.

    public void Return() throws ClassMakerException
    public void Return(Type type) throws ClassMakerException

The former method must be used for void methods and the latter for any method that returns a value.

A call to Return may be required as the last statement of a method, even if that call is unreachable.

Java codeClassMaker code
 
    String name;
 
    public String getName()
    {
        return name;
    }
     
    Method("getName", String.class, ACC_PUBLIC);    
    Begin();
        Return(Get(This(), "name"));
    End();
     
    protected int add(int a, int b)
    {
        return a + b;
    }
     
    maker.Method("add", int.class, ACC_PROTECTED);
    maker.Declare("a", int.class, 0);
    maker.Declare("b", int.class, 0);
    maker.Begin();
        maker.Return(maker.Add(maker.Get("a"), maker.Get("b")));    
    maker.End();

Calling methods

ClassMaker provides the following methods to perform methods calls.

    // Calls to non-static methods
    public Type Call(Type type, String methodName, CallStack actualParameters) throws ClassMakerException
    // Calls to static methods
    public Type Call(Class javaClass, String methodName, CallStack actualParameters) throws ClassMakerException
    public Type Call(String className, String methodName, CallStack actualParameters) throws ClassMakerException

The first version of Call is the one you will use most of the time. The other methods are used to generate calls
to static methods.

Java codeClassMaker code
    run();
    obj.run();
    obj = ExampleMethodsTest.getInstance();    
    Eval(Call(This(), "run", null));
    Eval(Call(Get(This(), "obj"), "run", null));
    Eval(Set(This(), "obj", Call(ExampleMethodsTest.class, "getInstance", null)));        

Calling methods with parameters

All of the Call methods above take a CallStack as their third parameter.
ClassMaker provides the following methods to create a call stack.

    public CallStack Push() throws ClassMakerException;
    public CallStack Push(Type param) throws ClassMakerException;
    public class CallStack
    {
        public CallStack Push(Type param) throws ClassMakerException;
    }

These methods can be daisy-chained together to create a call stack of actual parameters.
The Types on the call stack will be used by the method resolver to determine
which method to call.

    Push( <value1> ).Push( <value2> ).Push( <value3> );
Java codeClassMaker code
 
    x = add(1, 2);
    y = obj.add(x, 3);
    ExampleMethodsTest.setInstance(this);    
 
    Eval(Set(This(), "x", Call(This(), "add", Push(Literal(1)).Push(Literal(2)))));
    Eval(Set(This(), "y", Call(Get(This(), "obj"), "add", Push(Get(This(), "x")).Push(Literal(3)))));    
    Eval(Call(ExampleMethodsTest.class, "setInstance", Push(This())));

Note that Push() provides an empty CallStack. An empty CallStack will be created if
the callStack parameter is null.

Constructors

Two special methods are provided to assist with creating constructor methods.

    public void Init(ClassType classType, CallStack actualParameters) throws ClassMakerException
    public ClassType Super() throws ClassMakerException

The Init method is used to invoke a constructor method. The Super() method
pushes a reference to the current instance onto the stack. It differs from This()
in that it returns the type of the parent class.

Every class you generate must have at least one constructor. A typical
constructor looks like this.

    Method("<init>", void.class, ACC_PUBLIC);
    Begin();
        Init(Super(), null);
        Return();
    End();

You can provide your constructor either in the code() method
of ClassMakerBase or by overriding the special defaultConstructor() method.
ClassMakerBase will provide a default constructor if you don't.

A constructor method must be called "<init>" and must include a call to a
constructor in the super class with an appropriate CallStack.

    Init(Super(), ... );

Abstract methods

Interface methods and abstract methods do not have a body.
This is indicated in !ClassMaker using the Forward method.
This method is used instead of providing a body for the method being generated.

    public void Forward() throws ClassMakerException

An abstract method in an abstract class must be declared as such using the ClassMaker.ACC_ABSTRACT bit mask.
All methods in an interface are implicitly abstract so the ACC_ABSTRACT bit mask is optional.

Java codeClassMaker code
     
    public abstract int getId();
     
    public abstract void setId(int value);
     
    Method("getId", int.class, ACC_PUBLIC | ACC_ABSTRACT);
    Forward();
     
    Method("setId", void.class, ACC_PUBLIC | ACC_ABSTRACT);
    Declare("value", int.class, 0);
    Forward();

Forward declarations

ClassMaker is a single pass byte-code generator by default. This means that
a method cannot be used until it has been declared. This creates a problem if two
methods mutually call each other. ClassMaker resolves this issue by allowing
methods to be forward declared using the Forward method.

    public void Forward() throws ClassMakerException

Methods that are used before they are declared must be declared twice. The
first time the method is declared without a body using the Forward method.
This declaration must occur before the method is first used.
The second declaration of the method, which provides the body of the method,
may be declared anywhere after the forward declaration.
Both the forward declaration and the actual declaration of the method must
have the same parameters otherwise the generator will complain.

    maker.Method("add", int.class, ClassMaker.ACC_PRIVATE);
    maker.Declare("a", int.class, 0);
    maker.Declare("b", int.class, 0);
    maker.Forward();
     
    maker.Method("eval", int.class, ClassMaker.ACC_PUBLIC);
    maker.Begin();
        maker.Return(maker.Call(maker.This(), "add", maker.Push(maker.Literal(1)).Push(maker.Literal(2))));
    maker.End();
     
    maker.Method("add", int.class, ClassMaker.ACC_PRIVATE);
    maker.Declare("a", int.class, 0);
    maker.Declare("b", int.class, 0);
    maker.Begin();
        maker.Return(maker.Add(maker.Get("a"), maker.Get("b")));
    maker.End();

In this example the add method is forward declared and then called in the eval method.
The actual declaration of the add method occurs after it is first used.

There is no equivalent in java of a forward declaration, however there is forward declaration
in C and C++ which are the predecessors of java and upon which the java syntax is based. The
original Kernigan and Richie (K&R) C also had a style of declaring formal parameters similar to that
used in ClassMaker.

Note that ClassMaker may be configured to be a two pass code generator, in which case it is
not necessary to forward declare methods.

Recursive data structures

There are times when a class needs to refer to itself, such as when building recursive data structures
like linked lists and binary trees.
This method returns the Type of the class currently being generated.

    public ClassType getClassType()

The following example shows how one might recursively search through a linked list.

Java codeClassMaker code
    String name;
    Link   next;
     
    public Link find(String target)
    {
        if (target.equals(name))
            return this;
        else
            return next.find(target);
    }
    Declare("name", String.class, 0);
    Declare("next", getClassType(), 0);
     
    Method("find", getClassType(), ACC_PUBLIC);
    Declare("target", String.class, 0);
    Begin();
        If(Call(Get("target"), "equals", Push(Get(This(), "name"))));
            Return(This());
        Else();
            Return(Call(Get(This(), "next"), "find", Push(Get("target"))));
        EndIf();
    End();

[Home]


Related

Wiki: Home

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.