using System;
namespace Cryville.Common.Pdt {
///
/// PDT operator.
///
public unsafe abstract class PdtOperator {
byte* _prmem;
int _loadindex;
readonly PdtVariableMemory[] _operands;
///
/// The count of the operands loaded.
///
protected int LoadedOperandCount { get { return ParamCount - _loadindex; } }
///
/// Gets the operand at the specified index.
///
/// The index.
/// The operand at the specified index.
/// is not less than or less than 0.
protected PdtVariableMemory GetOperand(int index) {
if (index >= LoadedOperandCount || index < 0) throw new IndexOutOfRangeException();
int i = index + _loadindex;
return _operands[i];
}
internal int ParamCount { get; private set; }
///
/// Creates an instance of the class.
///
/// The suggested parameter count.
protected PdtOperator(int pc) {
ParamCount = pc;
_operands = new PdtVariableMemory[pc];
}
PdtEvaluatorBase _etor;
bool _failure = false;
bool _rfreq = true;
internal void Begin(PdtEvaluatorBase etor) {
_etor = etor;
_failure = false;
_loadindex = ParamCount;
}
internal void LoadOperand(PdtVariableMemory mem) {
if (_loadindex == 0) return;
_operands[--_loadindex] = mem;
}
internal void Call(byte* prmem, bool noset) {
_prmem = prmem;
_rfreq = false;
Execute();
if (!_rfreq && !noset) throw new InvalidOperationException("Return frame not set");
if (_failure) {
if (_rfreq) _etor.DiscardStack();
throw new InvalidOperationException("Evaluation failed");
}
}
///
/// Executes the operator.
///
protected abstract void Execute();
///
/// Gets a return frame.
///
/// The type of the frame.
/// The length of the frame.
/// The return frame.
/// The return frame has already been requested.
protected PdtVariableMemory GetReturnFrame(int type, int len) {
if (_rfreq) {
_failure = true;
throw new InvalidOperationException("Return frame already requested");
}
_rfreq = true;
return _etor.StackAlloc(type, _prmem, len);
}
}
}