package jmathlib.core.tokens;
import jmathlib.core.functions.*;
import jmathlib.core.interpreter.*;
/**Class used to represent any functions used in the expression*/
public class FunctionToken extends OperandToken
{
/**The name of the function*/
private String name;
/**operands of this function*/
OperandToken[] operands;
/**Number of left-hand arguments (e.g. [a,b,c]=some_functions() ) */
private int noOfLeftHandArguments = 0;
/**Indicator if function is a class file or a m-script file */
private boolean scriptTag = false;
/**Indicator if function has been evaluated */
private boolean isEvaluatedB = false;
// Indicator wether or not the operands should be evaluated:
// e.g. global aa bb (then global needs aa=variable as input and
// not the value of aa
public boolean evaluationLockB = false;
/**constructor for function tokens
* @param _name = the name of the function
*/
public FunctionToken(String _name)
{
name = _name;
priority = 10;
}
/**constructor for function tokens
@param _name = the name of the function
@param _param = the first argument*/
public FunctionToken(String _name, OperandToken _firstParameter)
{
name = _name;
priority = 10;
operands = new OperandToken[1];
operands[0] = _firstParameter;
}
/**constructor for function tokens
@param _name = the name of the function
@param _param = the parameters of the function*/
public FunctionToken(String _name, OperandToken[] _parameters)
{
name = _name;
priority = 10;
operands = _parameters;
}
/**Sets the number of left-hand arguments of the function
(e.g.) [a,b,c]=some_function will return set a "3"
@param _number = the number of left hand arguments*/
public void setNoOfLeftHandArguments(int _number)
{
noOfLeftHandArguments = _number;
}
/**Return one of the operands
* @param index = index of operand
* @return operand = requested operand
*/
public OperandToken getOperand(int index)
{
if (operands == null)
return null;
if ((index >= operands.length) || (index <=0))
return null;
return operands[index];
}
/**Return all operands
@return operands = all operands of this function */
public OperandToken[] getOperands()
{
return operands;
}
/**Set operands of this function
@param _operands = operands of this function */
public void setOperands(OperandToken[] _operands)
{
operands = _operands;
}
/**Set first operand of this function
@param _operand = first operand of this function */
public void setOperand(OperandToken _operand)
{
operands = new OperandToken[1];
operands[0] = _operand;
}
/**Executes the function referenced by this token
* @param operands = the functions operands
* @param
* @return the result of the function as an OperandToken
*/
public OperandToken evaluate(Token[] _operands, GlobalValues globals)
{
Function function = null;
OperandToken result = null;
ErrorLogger.debugLine("FunctionToken: eval "+name);
//setGlobals(globals);
// special handling for "return" function
// throw control exception
if (name.equals("return"))
{
ErrorLogger.debugLine("FunctionToken: return: control exception");
throw new ControlException();
}
// check if the function is overloaded by a variable name
//if( getVariables().getVariable(name) != null)
if( globals.getVariable(name) != null)
{
// Variable overloads function
ErrorLogger.debugLine("FunctionToken: eval: variable overloads function");
// create variable and set parameters of this function as limits of variable
VariableToken varToken = new VariableToken(name, operands);
// evaluate variable with limits and return result
return varToken.evaluate(null, globals);
}
// Function is not overloaded by a variable
// Now try to find the function
try
{
function = globals.getFunctionManager().findFunction(this);
}
catch(Exception exception)
{
Errors.throwMathLibException(ERR_FUNCTION_NOT_FOUND, new Object[] {name});
}
// Check wether or not the function was found
if(function != null)
{
// Function has been found
if (function instanceof UserFunction)
if (((UserFunction)function).isScript())
scriptTag = true;
// Set the number of left-hand arguments for return value processing
function.setNoOfLeftHandArguments(noOfLeftHandArguments);
ErrorLogger.debugLine("FunctionToken eval = " + name);
// evaluate operands first
// do not evaluate if evaluationLock is set (e.g. global aa bb cc)
if ((operands != null) && (!evaluationLockB))
{
for (int i=0; i<operands.length; i++)
{
operands[i]=operands[i].evaluate(null, globals);
}
}
// evaluate function with its operands
// If the function if of type UserFunction it has to be cloned so that
// the original m-function or m-script stays untouched
if (function instanceof UserFunction)
result = ((Function)function.clone()).evaluate(operands, globals);
else
result = function.evaluate(operands, globals);
// remember that this function has been evaluated
// (important for functions which are overloading variables (e.g. who ))
isEvaluatedB = true;
// check for ???
//if ((operands != null) && (operands.length > 0))
//{
// if(result == null)
// {
// result = this;
// }
//}
ErrorLogger.debugLine("FunctionToken result = "+result);
return result;
} // end function!=null
Errors.throwMathLibException("FunctionToken: undefinded variable or function "+name);
return result;
} // end evaluate
/** Getter method,
@return true is the function is not a function but an m-script file*/
public boolean isScript()
{
return scriptTag;
}
/** Getter method,
@return true is the function has been evaluated*/
public boolean isEvaluated()
{
return isEvaluatedB;
}
/**Getter method,
@return the functions name*/
public String getName()
{
return name;
}
/**Tests if an object is equal to this function
@param obj = object to test
if obj is an instance of Function or Function token then it
compares the name of obj to the functions name otherwise it
calls the superclasses version
@return true if they are equal*/
public boolean equals(Object obj)
{
boolean equal = false;
if(obj instanceof Function)
{
equal = ((Function)obj).getName().toUpperCase().equals(name.toUpperCase());
}
else if(obj instanceof FunctionToken)
{
equal = ((FunctionToken)obj).getName().toUpperCase().equals(name.toUpperCase());
}
else
equal = super.equals(obj);
return equal;
}
/**@return the function as a string*/
public String toString()
{
String result = name + "(";
if (operands == null)
return null;
for (int i=0; i<operands.length; i++)
{
if (operands[i] != null)
{
result += operands[i].toString();
if (i < (operands.length-1))
{
if (operands[i+1] != null) result += ",";
}
}
}
result += ")";
return result;
}
}