namespace HeuristicLab.Problems.ProgramSynthesis.Push.Expressions {
using System;
using Attributes;
using Interpreter;
using Persistence.Default.CompositeSerializers.Storable;
using Stack;
///
/// Like CODE.DO*COUNT but does not push the loop counter.
/// This should be implemented as a macro that expands into CODE.DO*RANGE, similarly to the implementation
/// of CODE.DO*COUNT, except that a call to INTEGER.POP should be tacked on to the front of the loop body code
/// in the call to CODE.DO*RANGE.
///
[Serializable]
[StorableClass]
[PushExpression(StackTypes.Code, "CODE.DO*TIMES", "Like CODE.DO*COUNT but does not push the loop counter", StackTypes.Integer)]
public class CodeDoTimesExpression : StatelessExpression {
public CodeDoTimesExpression() { }
[StorableConstructor]
protected CodeDoTimesExpression(bool deserializing) : base(deserializing) { }
public override void Eval(IInternalPushInterpreter interpreter) {
var destinationIndex = Math.Max(0, interpreter.IntegerStack.Top - 1);
if (destinationIndex == 0) {
interpreter.IntegerStack.Pop();
interpreter.ExecStack.Push((PushProgram)interpreter.CodeStack.Pop());
return;
}
interpreter.IntegerStack.Top = 0;
interpreter.IntegerStack.Push(destinationIndex);
var popExpressions = ExpressionTable.GetStatelessExpression();
PushProgram program;
if (!interpreter.CodeStack.Top.IsProgram) {
var expressions = interpreter.PoolContainer.ExpressionListPool.Get();
expressions.Add(interpreter.ExecStack.Top);
expressions.Add(popExpressions);
program = PushProgram.Create(interpreter.PoolContainer.PushProgramPool, expressions);
} else {
program = PushProgram.Merge(
interpreter.PoolContainer.PushProgramPool,
interpreter.PoolContainer.ExpressionListPool,
(PushProgram)interpreter.CodeStack.Top,
popExpressions);
}
interpreter.CodeStack.Top = program;
interpreter.ExecStack.Push(ExpressionTable.GetStatelessExpression());
}
public override bool IsNoop(IInternalPushInterpreter interpreter) {
return interpreter.IntegerStack.IsEmpty ||
interpreter.IntegerStack.Top < 0 ||
interpreter.CodeStack.IsEmpty;
}
}
///
/// Like EXEC.DO*COUNT but does not push the loop counter. This should be implemented as a macro that expands into
/// EXEC.DO*RANGE, similarly to the implementation of EXEC.DO*COUNT, except that a call to INTEGER.POP should be tacked on to the
/// front of the loop body code in the call to EXEC.DO*RANGE. This call to INTEGER.POP will remove the loop counter, which will have
/// been pushed by EXEC.DO*RANGE, prior to the execution of the loop body.
///
[Serializable]
[StorableClass]
[PushExpression(StackTypes.Exec, "EXEC.DO*TIMES", "Like EXEC.DO*COUNT but does not push the loop counter", StackTypes.Integer, requiredBlockCount: 1)]
public class ExecDoTimesExpression : StatelessExpression {
public ExecDoTimesExpression() { }
[StorableConstructor]
protected ExecDoTimesExpression(bool deserializing) : base(deserializing) { }
public override void Eval(IInternalPushInterpreter interpreter) {
var destinationIndex = Math.Max(0, interpreter.IntegerStack.Top - 1);
if (destinationIndex == 0) {
interpreter.IntegerStack.Pop();
return;
}
interpreter.IntegerStack.Top = 0;
interpreter.IntegerStack.Push(destinationIndex);
var popExpressions = ExpressionTable.GetStatelessExpression();
PushProgram program;
if (!interpreter.ExecStack.Top.IsProgram) {
var expressions = interpreter.PoolContainer.ExpressionListPool.Get();
expressions.Add(interpreter.ExecStack.Top);
expressions.Add(popExpressions);
program = PushProgram.Create(interpreter.PoolContainer.PushProgramPool, expressions);
} else {
program = PushProgram.Merge(
interpreter.PoolContainer.PushProgramPool,
interpreter.PoolContainer.ExpressionListPool,
(PushProgram)interpreter.ExecStack.Top,
popExpressions);
}
interpreter.ExecStack.Top = program;
interpreter.ExecStack.Push(ExpressionTable.GetStatelessExpression());
}
public override bool IsNoop(IInternalPushInterpreter interpreter) {
return interpreter.IntegerStack.IsEmpty ||
interpreter.IntegerStack.Top < 0 ||
interpreter.ExecStack.IsEmpty;
}
}
}