gt: 			value = evaluateExpression(t.getChild(0));
context: /**
   * Copyright (c) 2011, Jordi Cortadella
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *    * Redistributions of source code must retain the above copyright
   *      notice, this list of conditions and the following disclaimer.
   *    * Redistributions in binary form must reproduce the above copyright
   *      notice, this list of conditions and the following disclaimer in the
   *      documentation and/or other materials provided with the distribution.
   *    * Neither the name of the <organization> nor the
   *      names of its contributors may be used to endorse or promote products
   *      derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  package interp;
  
  import parser.*;
  import CRAP.*;
  
  import java.time.Instant;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Random;
  import java.util.Scanner;
  
  import javax.management.RuntimeErrorException;
  
  import java.io.*;
  
  import CRAP.CRAP;
  import CRAP.Timeline;
  import CRAP.Tween;
  import CRAP.TweenManager;
  
  /** Class that implements the interpreter of the language. */
  
  public class Interp {
  	private String currentInterpType;
  	private float currentKeyTimeAbs = 0.0f;
  	private float timeScopeStartAbs = 0.0f;
  	private float timeScopeFinishAbs = 1.0f;
  
  	public TimelineManager timelineManager;
  	public TweenManager tweenManager;
  
  	/** Memory of the virtual machine. */
  	public Stack stack;
  
  	/**
  	 * Map between function names (keys) and ASTs (values). Each entry of the
  	 * map stores the root of the AST correponding to the function.
  	 */
  	private HashMap<String, CRAPTree> FuncName2Tree;
  
  	/** Standard input of the interpreter (System.in). */
  	private Scanner stdin;
  
  	/**
  	 * Stores the line number of the current statement. The line number is used
  	 * to report runtime errors.
  	 */
  	private int linenumber = -1;
  
  	/** File to write the trace of function calls. */
  	private PrintWriter trace = null;
  
  	/** Nested levels of function calls. */
  	private int function_nesting = -1;
  
  	/**
  	 * Constructor of the interpreter. It prepares the main data structures for
  	 * the execution of the main program.
  	 */
  	public Interp(CRAPTree T, String tracefile) {
  		assert T != null;
  		stack = new Stack(); // Creates the memory of the virtual machine
  		stack.pushActivationRecord("__global", 0);
  		Data light0 = new Data(), light1 = new Data(), light2 = new Data();
  		light0.ConvertToObject(); light1.ConvertToObject(); light2.ConvertToObject();
  		light0.setProperty("Primitive", new Data("Light"));
  		light1.setProperty("Primitive", new Data("Light"));
  		light2.setProperty("Primitive", new Data("Light"));
  		stack.defineVariable("Light0", light0);
  		stack.defineVariable("Light1", light1);
  		stack.defineVariable("Light2", light2);
  		light0.setProperty("Visible", new Data(false));
  		light1.setProperty("Visible", new Data(false));
  		light2.setProperty("Visible", new Data(false));
  		light0.setProperty("Range", new Data(1.0f));
  		light1.setProperty("Range", new Data(1.0f));
  		light2.setProperty("Range", new Data(1.0f));
  		light0.setProperty("Intensity", new Data(64.0f));
  		light1.setProperty("Intensity", new Data(64.0f));
  		light2.setProperty("Intensity", new Data(64.0f));
  
  		MapFunctions(T); // Creates the table to map function names into AST
  							// nodes
  		PreProcessAST(T); // Some internal pre-processing ot the AST
  
  		// Initializes the standard input of the program
  		stdin = new Scanner(
  				new BufferedReader(new InputStreamReader(System.in)));
  		if (tracefile != null) {
  			try {
  				trace = new PrintWriter(new FileWriter(tracefile));
  			} catch (IOException e) {
  				System.err.println(e);
  				System.exit(1);
  			}
  		}
  		function_nesting = -1;
  	}
  
  	public void Init() {
  		tweenManager = new TweenManager();
  		timelineManager = new TimelineManager(this);
  
  		Timeline mainTimeline = new Timeline("Main", new ArrayList<Data>(),
  				0.0f, 1.0f);
  		executeTimeline(mainTimeline);
  	}
  
  	public void Update() {
  		tweenManager.Update();
  		timelineManager.Update();
  	}
  
  	/** Returns the contents of the stack trace */
  	public String getStackTrace() {
  		return stack.getStackTrace(lineNumber());
  	}
  
  	/** Returns a summarized contents of the stack trace */
  	public String getStackTrace(int nitems) {
  		return stack.getStackTrace(lineNumber(), nitems);
  	}
  
  	/**
  	 * Gathers information from the AST and creates the map from function names
  	 * to the corresponding AST nodes.
  	 */
  	private void MapFunctions(CRAPTree T) {
  		assert T != null && T.getType() == CRAPLexer.LIST_FUNCTIONS;
  
  		// Map globals and functions
  		FuncName2Tree = new HashMap<String, CRAPTree>();
  		int n = T.getChildCount();
  		for (int i = 0; i < n; ++i) {
  			CRAPTree f = T.getChild(i);
  			String fname = f.getChild(0).getText();
  			switch (f.getType()) {
  			case CRAPLexer.GLOBAL:
  				Data globalVariable = new Data();
  				globalVariable.setType(Data.Type.OBJECT);
  				stack.defineVariable(fname, globalVariable);
  				break;
  
  			case CRAPLexer.PREFAB:
  			case CRAPLexer.TIMELINE:
  			case CRAPLexer.FUNCTION:
  				if (FuncName2Tree.containsKey(fname)) {
  					throw new RuntimeException(
  							"Multiple definitions of function " + fname);
  				}
  				FuncName2Tree.put(fname, f);
  				break;
  			}
  		}
  	}
  
  	/**
  	 * Performs some pre-processing on the AST. Basically, it calculates the
  	 * value of the literals and stores a simpler representation. See
  	 * CRAPTree.java for details.
  	 */
  	private void PreProcessAST(CRAPTree T) {
  		if (T == null)
  			return;
  		switch (T.getType()) {
  		case CRAPLexer.NUMBER:
  			T.setFloatValue();
  			break;
  		case CRAPLexer.STRING:
  			T.setStringValue();
  			break;
  		case CRAPLexer.BOOLEAN:
  			T.setBooleanValue();
  			break;
  		default:
  			break;
  		}
  		int n = T.getChildCount();
  		for (int i = 0; i < n; ++i)
  			PreProcessAST(T.getChild(i));
  	}
  
  	/**
  	 * Gets the current line number. In case of a runtime error, it returns the
  	 * line number of the statement causing the error.
  	 */
  	public int lineNumber() {
  		return linenumber;
  	}
  
  	/** Defines the current line number associated to an AST node. */
  	private void setLineNumber(CRAPTree t) {
  		linenumber = t.getLine();
  	}
  
  	/** Defines the current line number with a specific value */
  	private void setLineNumber(int l) {
  		linenumber = l;
  	}
  
  	private Data executeFunction(String funcName, CRAPTree args, Timeline timeline, Data thisRef) {
  		// Get the AST of the function
  		CRAPTree f = FuncName2Tree.get(funcName);
  		if (f == null)
  			throw new RuntimeException(" function " + funcName
  					+ " not declared");
  
  		// Gather the list of arguments of the caller. This function
  		// performs all the checks required for the compatibility of
  		// parameters.
  		ArrayList<Data> Arg_values = timeline == null ? listArguments(f, args)
  				: timeline.GetArgs();
  
  		// Dumps trace information (function call and arguments)
  		if (trace != null)
  			traceFunctionCall(f, Arg_values);
  
  		// List of parameters of the callee
  		CRAPTree p = f.getChild(1);
  		int nparam = p.getChildCount(); // Number of parameters
  
  		// Create the activation record in memory
  		stack.pushActivationRecord(funcName, lineNumber());
  		
  		if (thisRef != null)
  		{
  			stack.defineVariable("this", thisRef);
  		}
  
  		if (timeline != null) {
  			timeline.SetActivationRecord(stack.GetCurrentActivationRecord());
  		}
  
  		// Track line number
  		setLineNumber(f);
  
  		// Copy the parameters to the current activation record
  		for (int i = 0; i < nparam; ++i) {
  			String param_name = p.getChild(i).getText();
  			stack.defineVariable(param_name, Arg_values.get(i));
  		}
  
  		// Execute the instructions
  		Data result = executeListInstructions(f.getChild(2));
  
  		// If the result is null, then the function returns void
  		if (result == null)
  			result = new Data();
  
  		// Dumps trace information
  		if (trace != null)
  			traceReturn(f, result, Arg_values);
  
  		// Destroy the activation record
  		stack.popActivationRecord();
  
  		return result;
  	}
  
  	private Data executeFunction(String funcName, CRAPTree args) {
  		return executeFunction(funcName, args, null, null);
  	}
  
  	public Data executeTimeline(Timeline timeline) 
  	{
  		timeScopeStartAbs = timeline.GetStartTimeAbs();
  		timeScopeFinishAbs = timeline.GetFinishTimeAbs();
  
  		Data d = executeFunction(timeline.GetName(), null, timeline, null);
  		return d;
  	}
  
  	/**
  	 * Executes a block of instructions. The block is terminated as soon as an
  	 * instruction returns a non-null result. Non-null results are only returned
  	 * by "return" statements.
  	 * 
  	 * @param t
  	 *            The AST of the block of instructions.
  	 * @return The data returned by the instructions (null if no return
  	 *         statement has been executed).
  	 */
  	private Data executeListInstructions(CRAPTree t) {
  		assert t != null;
  		Data result = null;
  		int ninstr = t.getChildCount();
  		for (int i = 0; i < ninstr; ++i) {
  			result = executeInstruction(t.getChild(i));
  			if (result != null)
  				return result;
  		}
  		return null;
  	}
  
  	/**
  	 * Executes an instruction. Non-null results are only returned by "return"
  	 * statements.
  	 * 
  	 * @param t
  	 *            The AST of the instruction.
  	 * @return The data returned by the instruction. The data will be non-null
  	 *         only if a return statement is executed or a block of instructions
  	 *         executing a return.
  	 */
  	private Data executeInstruction(CRAPTree t) {
  		assert t != null;
  
  		setLineNumber(t);
  		Data value = new Data(); // The returned value
  
  		// A big switch for all type of instructions
  		switch (t.getType()) {
  		case CRAPLexer.ASSIGN: {
  			value = evaluateExpression(t.getChild(1));
  			
  			CRAPTree var = t.getChild(0);
  			String baseVar = var.getChild(0).getText();
  
  			if (var.getChildCount() == 1) {
  				value = value.isObject() ? value : new Data(value);
  				stack.defineVariable(baseVar, value);
  				return null;
  			}
  
  			Data data = stack.getVariable(baseVar);
  
  			for (int i = 1; i < var.getChildCount() - 1; ++i) {
  				CRAPTree vari = var.getChild(i);
  
  				String index = vari.getType() == CRAPLexer.ARR_INDEX ? evaluateExpression(
  						vari.getChild(0)).toArrIndex()
  						: vari.getText();
  
  				data = data.getProperty(index);
  			}
  
  			CRAPTree index = var.getLastChild();
  			String indexStr = index.getType() == CRAPLexer.ARR_INDEX ? evaluateExpression(
  					index.getChild(0)).toArrIndex()
  					: index.getText();
  
  			if (data.isVec()) {
  				float[] values = value.isVec() ? value.getVecValue()
  						.GetValues() : new float[] { value.getNumberValue() };
  				data.getVecValue().Swizzle(indexStr, values);
  			} else {
  				value = value.isObject() ? value : new Data(value);
  				data.setProperty(indexStr, value);
  			}
  			
  			return null;
  		}
  
  		case CRAPLexer.TWEEN: {
  			CRAPTree var = t.getChild(0);
  			Data dataToTween = stack.getVariable(var.getChild(0).getText());
  
  			boolean isSwizzling = false;
  			String swizzle = "";
  			for (int i = 1; i < var.getChildCount(); ++i) {
  				if (dataToTween.isVec()) {
  					isSwizzling = i < var.getChildCount();
  					CRAPTree vari = var.getChild(i);
  					swizzle = vari.getType() == CRAPLexer.ARR_INDEX ? evaluateExpression(
  							vari.getChild(0)).toArrIndex()
  							: vari.getText();
  					break;
  				}
  
  				CRAPTree vari = var.getChild(i);
  				String index = vari.getType() == CRAPLexer.ARR_INDEX ? evaluateExpression(
  						vari.getChild(0)).toArrIndex()
  						: vari.getText();
  
  				dataToTween = dataToTween.getProperty(index);
  			}
  
  			Data finalValue = evaluateExpression(t.getChild(1));
  
  			if (isSwizzling) {
  				Vec v = new Vec(dataToTween.getVecValue());
  				if (!finalValue.isVec()) {
  					if (swizzle.length() > 1)
  						throw new RuntimeException(
  								"Tweening a vector to a wrong type.");
  					if (!finalValue.isNumber())
  						throw new RuntimeException(
  								"Tweening a vector to a non numeric value.");
  					v.Set(swizzle, finalValue.getNumberValue());
  				} else {
  					v.Swizzle(swizzle, finalValue.getVecValue().GetValues());
  				}
  				finalValue = new Data(v);
  			}
  
  			Tween tween = new Tween(dataToTween, currentKeyTimeAbs, finalValue,
  					currentInterpType);
  
  			tweenManager.AddTween(tween);
  			return null;
  		}
  
  		// If-then-else
  		case CRAPLexer.IF:
  