package codeline;

import processor.ControlFlow;
import processor.Memory;
import processor.Memory.ReadOnlyMemory;
import processor.Memory.Visibility;

/**
 * a line of code that declares a new variable
 * @author kolja
 *
 * @param <T> the type of the variable
 */
public abstract class DeclareVariable <T> extends CodeLine {

	private boolean oldExists;
	private String name;
	private Visibility vis;
    
	/**
	 * create the line of pseudo code (not the variable)
	 * @param name the name of the variable
	 */
    public DeclareVariable( String name )
    {
        this.name = name;
        this.vis = Visibility.LOCAL;
    }

    /**
     * create the line of pseudo code (not the variable)
     * @param name the name of the variable
     * @param vis the visibility of the variable
     */
	public DeclareVariable( String name, Visibility vis )
	{
		this.name = name;
		this.vis = vis;
	}

	@Override
	public ControlFlow runForward(Memory m) {
		
		oldExists = m.isDefined( name, vis );
		T oldVal = m.read( name, vis );
		m.declare( name, value( m.createReadOnlyMemory() ), vis );
		actions.push( (Memory mem) -> {
			mem.undeclare( name, vis );
            if( oldExists )
				mem.write( name, oldVal, vis );
		});
		return new ControlFlow( ControlFlow.STEP_OVER );
	}
	
	/**
	 * returns the value that will be stored in the variable
     * @param m the memory in which the variables are stored
	 * @return the value
	 */
	protected abstract T value( ReadOnlyMemory m );
}
