/*

   Derby - Class org.apache.derby.iapi.services.compiler.MethodBuilder

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to you under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */

package org.apache.derby.iapi.services.compiler;

/**
	MethodBuilder is used to generate the code for a method.
	<P>

	The code for a method is built in a way that corresponds to the
	layout of the stack machine that is the Java Virtual Machine.
	Values are pushed on the stack, moved about on the stack
	and then popped off the stack by operations such as method
	calls. An understanding of hoe the JVM operates is useful
	before using this class.

	<P>
	All the method descriptions below are generating bytecode
	to achieved the desired behaviour when the generated class
	is loaded. None of this class's methods calls actually
	invoke methods or create objects described by the callers.
 */
public interface MethodBuilder {

	/**
	 * Declare the method throws an exception.
	   Must be called before any code is added
	   to the method.
	 */
	public void addThrownException(String exceptionClass);

	/**
	 * return the name of the method.
	 */
	public String getName();

	/**
		Indicate the method is complete. Once this
		call has been made the caller must discard
		the reference to this object.
	 */
	public void complete();

	/**
		Push a parameter value.
		<PRE>
		Stack ...  =>
		      ...,param_value
		</PRE>
		@param id position of the parameter (zero based).
	*/
	public void getParameter(int id);

	/**
		Push a byte constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,byte_value
		</PRE>
	*/
	public void push(byte value);

	/**
		Push a boolean constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,boolean_value
		</PRE>
	*/
	public void push(boolean value);

	/**
		Push a short constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,short_value
		</PRE>
	*/
	public void push(short value);

	/**
		Push a int constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,int_value
		</PRE>
	*/
	public void push(int value);

	/**
		Push a long constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,long_value
		</PRE>
	*/
	public void push(long value);

	/**
		Push a float constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,float_value
		</PRE>
	*/
	public void push(float value);

	/**
		Push a double constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,double_value
		</PRE>
	*/
	public void push(double value);

	/**
		Push a String constant onto the stack
		<PRE>
		Stack ...  =>
		      ...,String_value
		</PRE>
	*/
	public void push(String value);

	/**
		Push a typed null onto the stack
		<PRE>
		Stack ...  =>
		      ...,null
		</PRE>
	*/
	public void pushNull(String className);

	/**
		Push the contents of the local field onto the stack.
		This call pushes the this instance required to access the field itself.
		<PRE>
		Stack ...  =>
		      ...,field_value
		</PRE>

	*/
	public void getField(LocalField field);

	/**
		Push the contents of the described field onto the stack.
		This call requires the instance (reference) to be pushed by the caller.

		<PRE>
		Stack ...,field_ref  =>
		      ...,field_value
		</PRE>
		
	*/
	public void getField(String declaringClass, String fieldName, String fieldType);

	/**
		Push the contents of the described static field onto the stack.
		<PRE>
		Stack ...  =>
		      ...,field_value
		</PRE>
	*/
	public void getStaticField(String declaringClass, String fieldName, String fieldType);

	/**
	Pop the top stack value and store it in the local field. 
	This call pushes the this instance required to access the field itself.
	This call does not leave any value on the stack.

	<PRE>
	Stack ...,value  =>
	      ...
	</PRE>
	*/
	public void setField(LocalField field);

	/**
		Pop the top stack value and store it in the local field. 
		This call pushes the this instance required to access the field itself.
		Like the Java language 'field = value', this leaves the value on the stack.

		<PRE>
		Stack ...,value  =>
		      ...,value
		</PRE>
	*/
	public void putField(LocalField field);

	/**
		Pop the top stack value and store it in the instance field of this class.
		This call pushes the this instance required to access the field itself.
		Like the Java language 'field = value', this leaves the value on the stack.

		<PRE>
		Stack ...,value  =>
		      ...,value
		</PRE>
	*/
	public void putField(String fieldName, String fieldType);

	/**
		Pop the top stack value and store it in the field.
		This call requires the instance to be pushed by the caller.
		Like the Java language 'field = value', this leaves the value on the stack.

		<PRE>
		Stack ...,field_ref,value  =>
		      ...,value
		</PRE>
	*/
	public void putField(String declaringClass, String fieldName, String fieldType);

	/**
		Initiate a sequence that calls a constructor, equivalent to the new operator in Java.
		After this call, the caller must push any arguments and then complete the
		construction with a call to pushNewComplete(). Only arguments to the constructor
		can be pushed onto the stack between the pushNewStart() and pushNewComplete() method
		calls.

		<PRE>
		Stack ... => [unchanged]
		      ...
		</PRE>

		@param className class name of object to be created.
	*/
	public void pushNewStart(String className);


	/**
		Complete the sequence that was started with pushNewStart().
		Pop the arguments to the constructor and push the reference
		to the newly created object.

		<PRE>
		Stack ...,value* => [numArgs number of values will be popped]
		      ...,new_ref
		</PRE>

		@param numArgs number of arguments to the constructor (can be 0).
	*/
	public void pushNewComplete(int numArgs);

	/**
		Create an instance of an array and push it onto the stack. 

		<PRE>
		Stack ...  =>
		      ...,array_ref
		</PRE>

		@param className - type of array.
		@param size - number of elements in the array
	*/
	public void pushNewArray(String className, int size);


	/**
		Push this onto the stack.
		<PRE>
		Stack ...  =>
		      ...,this_ref
		</PRE>
	*/
	public void pushThis();

	/**
		Upcast the top stack value. This is used for correct method resolution
		by upcasting method parameters. It does not put any casting code into the
		byte code stream. Can only be used for refrences.
		<PRE>
		Stack ...,ref =>
		      ...,ref
		</PRE>
	*/
	public void upCast(String className);

	/**
		Cast the top stack value. Correctly down-casts a reference or casts
		a primitive type (e.g. int to short).
		<PRE>
		Stack ...,value =>
		      ...,cast_value
		</PRE>

		@param className type (primitive, interface or class) to cast to.
	*/
	public void cast(String className);

	/**
		Pop the top stack value and push a boolean that is the result of
		an instanceof check on the popped reference.
		<PRE>
		Stack ...,ref =>
		      ...,boolean_value
		</PRE>.
	*/
	public void isInstanceOf(String className);
	
	/**
	 * Pop the top value off the stack
		<PRE>
		Stack ..., value =>
		      ...
		</PRE>.
	*/
	public void pop();
		
	/**
		End a statement.
		Pops the top-word of the stack, if any.
		Must only be called if zero or one item exists
		on the stack.
		<PRE>
		Stack value =>
		      :empty:
		or

		Stack :empty: =>
		      :empty:

		</PRE>.
	*/
	public void endStatement();

	/**
		Return from a method, optionally with a value.
		Must only be called if zero or one item exists
		on the stack. If the stack contains a single
		value then that is popped and used as the returned value.
		<PRE>
		Stack value =>
		      :empty:
		or

		Stack :empty: =>
		      :empty:

		</PRE>.
	*/
	public void methodReturn();

	/**
		Initiate a conditional sequence.
		The top value on the stack (a reference) is popped and compared to 'null'.
		If the value is null then the code following this call until the startElseCode()
		will be executed at runtime, otherwise the code following startElseCode() until
		the completeConditional() is called.
		<BR>
		E.g. 

		<PRE>
		mb.callMethod(...); // pushes an object onto the stack
		mb.conditionalIfNull();
		  mb.push(3);
		mb.startElseCode();
		  mb.push(5);
		mb.completeConditional();
		// at this point 3 or 5 will be on the stack
		</PRE>

		Each path through the ?: statement must leave the stack at the same depth
		as the other.
		<BR>
		If the if or else code pops values from the stack that were before the conditional
		value, then they must use the same number of values from the stack.

		<PRE>
		Stack ...,ref =>
		      ...
		</PRE>.

	*/

	public void conditionalIfNull();
	
	/**
		Initiate a conditional sequence.
		The top value on the stack must be a boolean and will be popped. If it
		is true then the code following this call until the startElseCode()
		will be executed at runtime, otherwise the code following startElseCode() until
		the completeConditional() is called. See conditionalIfNull() for example
		and restrictions.

		<PRE>
		Stack ...,boolean_value =>
		      ...
		</PRE>.
	*/
	public void conditionalIf();

	/**
		Complete the true code path of a conditional.
	*/
	public void startElseCode();

	/**
		Complete a conditional which completes the false code path.
	*/
	public void completeConditional();

	/**
		Call a method. The instance (receiver or reference) for non-static methods
		must be pushed by the caller. The instance (for non-static) and the arguments
		are popped of the stack, and the return value (if any) is pushed onto the stack.
		<BR>
		The type needs to be one of:
		<UL>
		<LI> VMOpcode.INVOKESTATIC - call a static method
		<LI> VMOpcode.INVOKEVIRTUAL - call method declared in the class or super-class.
		<LI> VMOpcode.INVOKEINTERFACE - call a method declared in an interface
		</UL>


		<PRE>
		static methods

		Stack ...,value* => [numArgs number of values will be popped]
		      ...,return_value [void methods will not push a value]

		non-static methods

		Stack ...,ref,value* => [numArgs number of values will be popped]
		      ...,return_value [void methods will not push a value]
		</PRE>

		<BR>
		The type of the arguments to the methods must exactly match the declared types
		of the parameters to the methods. If a argument is of the incorrect type the
		caller must up cast it or down cast it.

		@param type type of method invocation
		@param declaringClass Class or interface the method is declared in. If it is a non-static
			method call then if declaringClass is null, the declared type is taken to be the
			type of the reference that will be popped.

		@param methodName name of the method
		@param returnType class name or primitive type (including "void") of the return type of the method, can not be null.
		@param numArgs number of arguments to the method (can be 0).

	*/
	public int callMethod(short type, String declaringClass, String methodName,
		String returnType, int numArgs);

	/**	
		Return an object that efficiently (to the implementation) describes a zero-argument method and
		can be used with the single argument callMethod(). Descriptions for the parameters to this
		method are the same as the five argument callMethod(). This allows the caller to cache frequently
		used methods. The returned object is only valid for use by this MethodBuilder.
		<BR>
		This call does not affect the Stack.
	*/
	public Object describeMethod(short opcode, String declaringClass, String methodName, String returnType);

	/**
		Call a method previously described by describeMethod().
		<PRE>
		static methods

		Stack ...,value* => [numArgs number of values will be popped]
		      ...,return_value [void methods will not push a value]

		non-static methods

		Stack ...,ref,value* => [numArgs number of values will be popped]
		      ...,return_value [void methods will not push a value]
		</PRE>

	*/
	public int callMethod(Object methodDescriptor);

	/**
		Call super(). Caller must only add this to a constructor.
		<PRE>

		Stack ... =>
		      ... 
		</PRE>

	*/
	public void callSuper();

	/**
		Pop an array refrence off the stack and push an element from that array.
		<PRE>
		Stack ...,array_ref =>
		      ...,value
		</PRE>

		@param element Offset into the array (zero based)
	*/
	public void getArrayElement(int element);

	/**
		Pop an array reference off the stack, store a value in the array at the passed in offset.
		<PRE>
		Stack ...,array_ref, value =>
		      ...
		</PRE>

		@param element Offset into the array (zero based)
	*/
	public void setArrayElement(int element);


	/**
		Swap the top two values on the stack.
		<PRE>
		Stack ...,valueA,valueB =>
		      ...,valueB,valueA
		</PRE>
	*/
	public void swap();

	/**
		Duplicate the top value on the stack.
		<PRE>
		Stack ...,value =>
		      ...,value,value
		</PRE>
	*/
	public void dup();

	/**
		Tell if statement number in this method builder hits limit.  This
		method builder keeps a counter of how many statements are added to it.
		Caller should call this function every time it tries to add a statement
		to this method builder (counter is increased by 1), then the function
		returns whether the accumulated statement number hits a limit.
		The reason of doing this is that Java compiler has a limit of 64K code
		size for each method.  We might hit this limit if an extremely long
		insert statement is issued, for example (see beetle 4293).  Counting
		statement number is an approximation without too much overhead.
	*/
	public boolean statementNumHitLimit(int noStatementsAdded);
}

