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); } } }