package jmathlib.core.tokens;
import jmathlib.core.interpreter.*;
import jmathlib.core.constants.*;
import jmathlib.core.tokens.numbertokens.DoubleNumberToken;
import jmathlib.toolbox.jmathlib.matrix.*;
// !!!!! for NumberTokens I changed value to values[0][0]
// !!!!! THERE is MORE to do (stefan)
/**Class representing any variables used in an expression*/
public class VariableToken extends DataToken implements ErrorCodes
{
/**The variable name*/
private String name;
/** name for struct*/
private String fieldName;
/**The limits of this variable (e.g. a(2,3:5) )*/
private OperandToken[] limitTokens;
/**Boolean indicator if limits are active */
private boolean limitSwitch = false;
/** true if e.g. a{8}... */
private boolean cellB = false;
/**constructor containing the variables name
* @param _name = the name of the variable
*/
public VariableToken(String _name)
{
super(5, "variable");
name = _name;
fieldName = null;
}
/** constructor containing the variables name
* @param _name = the name of the variable
* @param _var = the variable being referenced
*/
public VariableToken(String _name, String _fieldName)
{
super(5, "variable");
name = _name;
fieldName = _fieldName;
}
/**constructor containing the variables name and limiting arguments
* @param _name = the name of the variable
* @param _operands = the limits of this variable (e.g. a(1,2:4) )
*/
public VariableToken(String _name, OperandToken[] _limits)
{
super(5, "variable");
name = _name;
fieldName = null;
this.setLimits(_limits);
}
/**constructor containing the variables name and limiting arguments
* @param _name = the name of the variable
* @param _operands = the limits of this variable (e.g. a(1,2:4) )
* @param _type = 'cell' if cell variable
*/
public VariableToken(String _name, OperandToken[] _limits, String _type)
{
super(5, "variable");
name = _name;
fieldName = null;
this.setLimits(_limits);
cellB = true;
}
/**@return true if the variable token has limits*/
public boolean isLimited()
{
return limitSwitch;
}
/**set limits for variable (e.g. a(1,3:4) )
@param limits = the limiting operands (DoubleNumberToken, ColonOperator) */
public void setLimits(OperandToken[] _limits)
{
ErrorLogger.debugLine("VariableToken: setLimits ");
// variable has limits
limitSwitch = true;
limitTokens = new OperandToken[_limits.length];
for(int childNo = 0; childNo < _limits.length; childNo++)
{
limitTokens[childNo] = (OperandToken)(_limits[childNo].clone());
}
/* // check and set limits of variable token
for(int childNo = 0; childNo < _limits.length; childNo++)
{
if(_limits[childNo] != null)
{
// do not evaluate something like "4:6" or ":" when it is a parameter
// of a function/variable
if (_limits[childNo] instanceof Expression)
{
if (!( ((Expression)_limits[childNo]).getData() instanceof ColonOperatorToken))
limitTokens[childNo] = _limits[childNo].evaluate(null);
else
limitTokens[childNo] = _limits[childNo];
}
else
{
limitTokens[childNo] = _limits[childNo].evaluate(null);
}
}
}
*/
} // end setlimits
/** return limits of this variable */
public OperandToken[] getLimits()
{
ErrorLogger.debugLine("VariableToken: getLimits");
return limitTokens;
}
/**@return the value of the data held within the variable
if the variable has not been inisitalised then it returns the variable*/
public OperandToken evaluate(Token[] operands, GlobalValues globals)
{
ErrorLogger.debugLine("VariableToken: eval: " + name);
//ErrorLogger.debugLine("VariableToken: evalG: " + globals);
// Check if variable is defined (in object storage)
if(fieldName != null)
{
//if(fieldName.equals("global")) //is this access to the global ascope
//{
// ErrorLogger.debugLine("getting global variable");
// return getGlobalVariables().getVariable(name).getData();
//}
//else
//{
ErrorLogger.debugLine("VariableToken: " + name + "getting field " + fieldName);
return ((MathLibObject)globals.getVariable(name).getData()).getFieldData(fieldName);
//}
}
else if( globals.getVariable(name) == null )
{
// variable is not yet defined (e.g. user typed sin(a) and "a" is unknown)
// or it is a function
// check for predefined variables
if (name.equals("pi"))
return new DoubleNumberToken(3.14159265358979);
if (name.equals("eps"))
return new DoubleNumberToken(2.2204e-016);
if (name.equals("e"))
return new DoubleNumberToken(2.718281828459046);
ErrorLogger.debugLine("VariableToken: var " + name + " not found: check functions");
// If it is not a variable maybe it's a function or script-file
FunctionToken function = new FunctionToken(name, limitTokens);
function.setOperands(new OperandToken[] {});
OperandToken retValue = function.evaluate(null, globals);
// if the "function" is really a script it won't return anything
if (function.isScript())
return null;
// if the functions returns something, also return that value
if (retValue != null)
return retValue;
// check if a function has been evluated
//(in case this functions returns null by default)
if (function.isEvaluated())
return null;
// all variables must be defined
Errors.throwMathLibException("VariableToken: undefined variable or function "+name);
return null;
}
// variable is defined already/now
// get data of variable
OperandToken variableData = globals.getVariable(name).getData();
// check if data is available
if(variableData != null)
{
ErrorLogger.debugLine("VariableToken data = " + variableData.toString());
// clone data so that original values are not changed
variableData = ((OperandToken)variableData.clone());
OperandToken result = variableData;
// check if variable has limits
if (limitSwitch && (result instanceof DataToken))
{
// create operand-array for SubMatrix() method
OperandToken[] opTok = new OperandToken[limitTokens.length + 1];
opTok[0] = variableData;
for (int i=0; i<limitTokens.length; i++)
{
//ErrorLogger.debugLine(i);
// clone limits functions/values to preserve for future evalutation
opTok[i+1] = ((OperandToken)limitTokens[i].clone());
opTok[i+1] = opTok[i+1].evaluate(null, globals);
if (opTok[i+1] != null)
ErrorLogger.debugLine("VariableToken: eval: toString("+i+") "+opTok[i+1].toString());
}
submatrix subM = new submatrix();
if (isCell())
{
ErrorLogger.debugLine("variable token: left is cell");
subM.setLeftCell();
}
// create instance of external function SubMatix and compute submatrix
result = subM.evaluate(opTok, globals);
}
/* display the result of this variable in the user console*/
if (isDisplayResult())
globals.getInterpreter().displayText(name +" = "+ result.toString(globals));
return result;
}
else
{
ErrorLogger.debugLine("Variable data = NULL");
// display the result of this variable in the user console
if (isDisplayResult())
globals.getInterpreter().displayText(name +" = []");
return null;
}
} // end eval
/**Implement the equals operator to find a VariableToken with the
correct name
@param _data = the object to match against
@return true if the are equal*/
public boolean equals(OperandToken _data)
{
boolean equal;
if(_data instanceof VariableToken)
equal = this.name.equals( ((VariableToken)_data).getName() );
else
equal = super.equals(_data);
ErrorLogger.debugLine("VariableToken equals "+_data.toString()+" "+equal);
return equal;
}
/**@return either the variable data as a string or the variable name*/
public String toString()
{
String result = name;
if(fieldName != null)
result = result + "." + fieldName;
return result;
}
/**return the name of the variable*/
public String getName()
{
return name;
}
/**return the name of the variable*/
public String getFieldName()
{
return fieldName;
}
/**return the data of the variable*/
/* public OperandToken getData()
{
if(fieldName == null)
return getVariable(name).getData();
else
return ((MathLibObject)getVariable(name).getData()).getFieldData(fieldName);
}
*/
public boolean equals(Object obj)
{
if(obj instanceof VariableToken)
{
VariableToken var = ((VariableToken)obj);
if(var.getName().equals(name))
return true;
}
return false;
}
/**Checks if this operand is a numeric value
@return true if this is a number, false if it's
an algebraic expression*/
/* public boolean isNumeric()
{
boolean numeric = false;
OperandToken data = null;
data = getVariable(name).getData();
if(data != null) //exchanged "this" with "name"
numeric = data.isNumeric();
return numeric;
}
*/
/**
* check if variable is a struct
* @return
*/
public boolean isStruct()
{
if (fieldName!=null)
return true;
else
return false;
}
/**
* check if variable is a cell array
* @return
*/
public boolean isCell()
{
return cellB;
}
/**get the variable that this token references*/
public Variable getVariable(GlobalValues globals)
{
if(fieldName == null)
return globals.getVariable(name);
if(globals.getVariable(name)!=null)
return ((MathLibObject)globals.getVariable(name).getData()).getFieldVariable(fieldName);
return null;
}
}