package pp.s1184725.boppi.symboltable;

import java.util.*;
import java.util.stream.Collectors;

import pp.s1184725.boppi.type.Type;

/**
 * Keeps track of local data for functions.
 *
 * @author Frank Wibbelink
 *
 * @param <T>
 *            the type system to use
 */
public class FunctionScope<T extends Type> {
	private final int scopeDepth;
	private List<Variable<T>> localVars;

	/**
	 * Creates a function scope with the given depth.
	 *
	 * @param depth
	 *            the lexical depth of this function
	 */
	public FunctionScope(int depth) {
		scopeDepth = depth;
		localVars = new ArrayList<>();
	}

	/**
	 * Creates a new variable in this function scope and returns it.
	 *
	 * @param type
	 *            the type of variable to create
	 * @return the variable created
	 */
	public Variable<T> addVariable(T type) {
		Variable<T> var = new Variable<T>(type, scopeDepth, getLocalDataSize());
		localVars.add(var);

		return var;
	}

	/**
	 * Returns the current lexical scope/function depth.
	 *
	 * @return the function depth
	 */
	public int getFunctionDepth() {
		return scopeDepth;
	}

	/**
	 * Returns the size, in bytes, required to store all the variables declared
	 * in the current function scope. Note that this is the size calculated up
	 * and including the last variable declaration, so make sure to call it
	 * right before leaving a function scope.
	 *
	 * @return the number of bytes required to store all variables local to a
	 *         function
	 */
	public int getLocalDataSize() {
		return localVars.stream().map(Variable::getType).collect(Collectors.summingInt(Type::getSize));
	}

	/**
	 * Returns the variables local to this function scope.
	 *
	 * @return a list of variables
	 */
	public List<Variable<T>> getVars() {
		return localVars;
	}

}
