120 lines
4.1 KiB
C#
120 lines
4.1 KiB
C#
using System;
|
|
|
|
namespace Cryville.Common.Pdt {
|
|
/// <summary>
|
|
/// PDT operator.
|
|
/// </summary>
|
|
public abstract unsafe class PdtOperator {
|
|
byte* _prmem;
|
|
int _loadindex;
|
|
readonly PdtVariableMemory[] _operands;
|
|
/// <summary>
|
|
/// The count of the operands loaded.
|
|
/// </summary>
|
|
protected int LoadedOperandCount { get; private set; }
|
|
/// <summary>
|
|
/// Gets the operand at the specified index.
|
|
/// </summary>
|
|
/// <param name="index">The index.</param>
|
|
/// <returns>The operand at the specified index.</returns>
|
|
/// <exception cref="IndexOutOfRangeException"><paramref name="index" /> is not less than <see cref="LoadedOperandCount" /> or less than 0.</exception>
|
|
protected PdtVariableMemory GetOperand(int index) {
|
|
if (index >= LoadedOperandCount || index < 0)
|
|
throw new ArgumentOutOfRangeException("index");
|
|
int i = index + _loadindex;
|
|
return _operands[i];
|
|
}
|
|
readonly int _pc;
|
|
/// <summary>
|
|
/// Creates an instance of the <see cref="PdtOperator" /> class.
|
|
/// </summary>
|
|
/// <param name="pc">The suggested parameter count.</param>
|
|
protected PdtOperator(int pc) {
|
|
_pc = pc;
|
|
_operands = new PdtVariableMemory[pc];
|
|
}
|
|
PdtEvaluatorBase _etor;
|
|
bool _rfreq = true;
|
|
internal void Begin(PdtEvaluatorBase etor, int pc) {
|
|
_etor = etor;
|
|
_loadindex = LoadedOperandCount = pc;
|
|
}
|
|
internal void LoadOperand(PdtVariableMemory mem) {
|
|
if (--_loadindex >= _pc) return;
|
|
_operands[_loadindex] = mem;
|
|
}
|
|
internal void Call(byte* prmem, bool noset) {
|
|
_prmem = prmem;
|
|
_rfreq = false;
|
|
try { Execute(); } catch (Exception ex) {
|
|
if (_rfreq) _etor.DiscardStack();
|
|
throw new EvaluationFailureException("Evaluation failed", ex);
|
|
}
|
|
if (!_rfreq && !noset) throw new EvaluationFailureException("Return frame not set");
|
|
}
|
|
/// <summary>
|
|
/// Executes the operator.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>When overridden, this method reads operands by calling <see cref="GetOperand(int)" />, and writes the result to the frame obtained by calling <see cref="GetReturnFrame(int, int)" />.</para>
|
|
/// </remarks>
|
|
protected abstract void Execute();
|
|
/// <summary>
|
|
/// Gets a return frame.
|
|
/// </summary>
|
|
/// <param name="type">The type of the frame.</param>
|
|
/// <param name="len">The length of the frame.</param>
|
|
/// <returns>The return frame.</returns>
|
|
/// <exception cref="InvalidOperationException">The return frame has already been requested.</exception>
|
|
protected PdtVariableMemory GetReturnFrame(int type, int len) {
|
|
if (_rfreq) throw new InvalidOperationException("Return frame requested twice");
|
|
_rfreq = true;
|
|
return _etor.StackAlloc(type, _prmem, len);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// The signature of a <see cref="PdtOperator" />.
|
|
/// </summary>
|
|
public struct PdtOperatorSignature : IEquatable<PdtOperatorSignature> {
|
|
/// <summary>
|
|
/// The name of the operator.
|
|
/// </summary>
|
|
public int Name { get; private set; }
|
|
/// <summary>
|
|
/// The parameter count.
|
|
/// </summary>
|
|
public int ParamCount { get; private set; }
|
|
readonly int _hash;
|
|
/// <summary>
|
|
/// Creates an operator signature.
|
|
/// </summary>
|
|
/// <param name="name">The name of the operator.</param>
|
|
/// <param name="paramCount">The parameter count.</param>
|
|
public PdtOperatorSignature(string name, int paramCount)
|
|
: this(IdentifierManager.SharedInstance.Request(name), paramCount) { }
|
|
/// <summary>
|
|
/// Creates an operator signature.
|
|
/// </summary>
|
|
/// <param name="name">The identifier of the operator.</param>
|
|
/// <param name="paramCount">The parameter count.</param>
|
|
public PdtOperatorSignature(int name, int paramCount) {
|
|
Name = name;
|
|
ParamCount = paramCount;
|
|
_hash = Name ^ ((ParamCount << 16) | (ParamCount >> 16));
|
|
}
|
|
public override bool Equals(object obj) {
|
|
if (!(obj is PdtOperatorSignature)) return false;
|
|
return Equals((PdtOperatorSignature)obj);
|
|
}
|
|
public bool Equals(PdtOperatorSignature other) {
|
|
return Name == other.Name && ParamCount == other.ParamCount;
|
|
}
|
|
public override int GetHashCode() {
|
|
return _hash;
|
|
}
|
|
public override string ToString() {
|
|
return string.Format("{0}({1})", IdentifierManager.SharedInstance.Retrieve(Name), ParamCount);
|
|
}
|
|
}
|
|
}
|