package Models.Expressions;

import Exceptions.BaseException;
import Models.Program.IDictionary;
import Models.Program.IHeap;
import Models.Types.IType;
import Models.Types.ReferenceType;
import Models.Values.IValue;
import Models.Values.ReferenceValue;

public class ReadHeap implements IExpression {
    private IExpression expression;

    public ReadHeap(IExpression expression) {
        this.expression = expression;
    }

    public IValue evaluate(IDictionary<String, IValue> table, IHeap heap) throws BaseException {
        IValue value = this.expression.evaluate(table, heap);
        if(!(value instanceof ReferenceValue)) {
            throw new BaseException("Expression is not a reference value");
        }
        int address = ((ReferenceValue)value).getAddress();
        if(!heap.contains(address)) {
            throw new BaseException("Address " + address + " is not in the heap");
        }
        return heap.get(address);
    }

    public IExpression copy() {
        return new ReadHeap(this.expression.copy());
    }

    public IType typeCheck(IDictionary<String, IType> typeTable) throws BaseException {
        IType type = this.expression.typeCheck(typeTable);
        if(!(type instanceof ReferenceType)) {
            throw new BaseException("Expression is not a reference value");
        }
        return ((ReferenceType)type).getInnerType();
    }
}
