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(); } }