package calculator.interpreter;
import java.util.List;
import calculator.interpreter.ast.Node;
import net.sf.etl.parsers.SourceLocation;
/**
* The variable
*/
public class Variable {
/** the name of variable to be defined */
public final String name;
/** the true value indicate that this name is mutable variable */
public final boolean isVar;
/** the true value indicate that is this name has been bound at least once */
public boolean isBound;
/** the value of the variable */
public Object value;
/** the location where variable is defined */
public final SourceLocation defineLocation;
/** the location where variable is set */
public SourceLocation bindLocation;
/** the documentation associated with binding (might be null) */
public final String documentation;
/** the annotation values (might be null) */
public final List<AnnotationValue> annotations;
/**
*The constructor for the variable
*
* @param previous the previous context (might be null)
* @param name the name of variable or constant
* @param isVar if true, the name could be rebound after it was bound
* @param defineLocation the location where the name was defined
* @param documentation the documentation associated with the variable
* @param annotations the list of annotation values
*/
public Variable(String name, boolean isVar, SourceLocation defineLocation,
String documentation, List<AnnotationValue> annotations) {
super();
this.name = name;
this.isVar = isVar;
this.defineLocation = defineLocation;
this.documentation = documentation;
this.annotations = annotations;
}
/**
* Get the value bound to the name
*
* @param node the node that requested the bind operation
* @return the current value of the binding
*/
public Object get(Node node) {
if (!isBound) {
throw new EvalException(node, "The name " + name + " defined at "
+ defineLocation.toShortString() + " has not been bound yet.");
}
return value;
}
/**
* Bind the variable with the value
*
* @param location the location of the node that requested the bind operation
* @param value the value to bind
* @return the value argument
*/
public Object bind(SourceLocation location, Object value) {
if (!isBound) {
isBound = true;
} else if (!isVar) {
throw new EvalException(location,
"The value has been already bound to constant " + name + " at "
+ bindLocation);
}
bindLocation = location;
this.value = value;
return value;
}
/**
* @return the help string for the variable
*/
public String help() {
StringBuilder b = new StringBuilder();
b.append("------ ");
b.append(isVar ? "Varaible " : "Constant ").append(name)
.append(" ------\n");
b.append("Defined at ").append(defineLocation.toShortString()).append('\n');
if (isBound) {
b.append("Bound at ").append(bindLocation.toShortString()).append(
" to value ").append(value).append('\n');
}
if (documentation == null) {
b.append("(No documentation defined)\n");
} else {
b.append(documentation);
}
if (annotations == null || annotations.size() == 0) {
b.append("(No annotations defined)\n");
} else {
for (AnnotationValue v : annotations) {
b.append(v).append('\n');
}
}
return b.toString();
}
}