Add project files.
This commit is contained in:
155
Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs
Normal file
155
Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// Base of evaluator for PDT expressions.
|
||||
/// </summary>
|
||||
public abstract class PdtEvaluatorBase {
|
||||
private struct StackFrame {
|
||||
public int Offset;
|
||||
public int Length;
|
||||
public int Type;
|
||||
}
|
||||
int _framecount = 0;
|
||||
int _goffset = 0;
|
||||
readonly StackFrame[] _stack = new StackFrame[256];
|
||||
readonly byte[] _mem = new byte[0x100000];
|
||||
bool _revokepttconst;
|
||||
/// <summary>
|
||||
/// Evaluates an expression and passes the result to a target operator.
|
||||
/// </summary>
|
||||
/// <param name="target">The target operator.</param>
|
||||
/// <param name="exp">The expression to evaluate.</param>
|
||||
public void Evaluate(PdtOperator target, PdtExpression exp) {
|
||||
_framecount = 0;
|
||||
_goffset = 0;
|
||||
_revokepttconst = false;
|
||||
for (var ins = exp.Instructions.First; ins != null; ins = ins.Next)
|
||||
ins.Value.Execute(this);
|
||||
Operate(target, _framecount, true);
|
||||
if (exp.IsPotentialConstant) {
|
||||
exp.IsConstant = exp.IsPotentialConstant = !_revokepttconst;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Optimizes an expression by merging its instructions.
|
||||
/// </summary>
|
||||
/// <param name="exp">The expression to optimize.</param>
|
||||
public void Optimize(PdtExpression exp) {
|
||||
_framecount = 0;
|
||||
_goffset = 0;
|
||||
var il = exp.Instructions;
|
||||
for (var ins = il.First; ins != null; ins = ins.Next) {
|
||||
var i = ins.Value;
|
||||
if (i is PdtInstruction.Operate) {
|
||||
int fc0 = _framecount;
|
||||
int fc1 = ((PdtInstruction.Operate)i).ParamCount;
|
||||
try { i.Execute(this); } catch (Exception) { }
|
||||
if (fc0 - _framecount == fc1) {
|
||||
unsafe {
|
||||
fixed (StackFrame* frame = &_stack[_framecount++]) {
|
||||
frame->Type = PdtInternalType.Error;
|
||||
frame->Offset = -1;
|
||||
frame->Length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var frame = _stack[_framecount - 1];
|
||||
il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length));
|
||||
ins = ins.Next;
|
||||
for (var j = 0; j <= fc1; j++) il.Remove(ins.Previous);
|
||||
}
|
||||
}
|
||||
else if (i is PdtInstruction.PushVariable) {
|
||||
i.Execute(this);
|
||||
var frame = _stack[_framecount - 1];
|
||||
if (frame.Type != PdtInternalType.Undefined) {
|
||||
il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length));
|
||||
ins = ins.Next;
|
||||
il.Remove(ins.Previous);
|
||||
}
|
||||
}
|
||||
else i.Execute(this);
|
||||
}
|
||||
exp.IsConstant = true;
|
||||
exp.IsPotentialConstant = true;
|
||||
for (var ins = il.First; ins != null; ins = ins.Next) {
|
||||
if (!(ins.Value is PdtInstruction.PushConstant)) {
|
||||
exp.IsConstant = false;
|
||||
}
|
||||
else if (!(ins.Value is PdtInstruction.PushVariable)) {
|
||||
exp.IsPotentialConstant = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Revokes the potential constant mark of the current expression.
|
||||
/// </summary>
|
||||
protected void RevokePotentialConstant() {
|
||||
_revokepttconst = true;
|
||||
}
|
||||
internal unsafe void PushConstant(int type, byte[] value) {
|
||||
fixed (StackFrame* frame = &_stack[_framecount++]) {
|
||||
frame->Type = type;
|
||||
frame->Offset = _goffset;
|
||||
frame->Length = value.Length;
|
||||
Array.Copy(value, 0, _mem, _goffset, value.Length);
|
||||
_goffset += value.Length;
|
||||
}
|
||||
}
|
||||
internal unsafe void PushVariable(ref string name) {
|
||||
fixed (StackFrame* frame = &_stack[_framecount++]) {
|
||||
byte[] value;
|
||||
GetVariable(name, out frame->Type, out value);
|
||||
frame->Offset = _goffset;
|
||||
frame->Length = value.Length;
|
||||
Array.Copy(value, 0, _mem, _goffset, value.Length);
|
||||
_goffset += value.Length;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a variable of the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the variable.</param>
|
||||
/// <param name="type">The type of the variable.</param>
|
||||
/// <param name="value">The value of the variable.</param>
|
||||
protected abstract void GetVariable(string name, out int type, out byte[] value);
|
||||
internal void Operate(ref string name, int pc) {
|
||||
Operate(GetOperator(name, pc), pc);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets an operator of the specified name and the suggested parameter count.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the operator.</param>
|
||||
/// <param name="pc">Suggested parameter count.</param>
|
||||
/// <returns>An operator of the specific name.</returns>
|
||||
/// <remarks>The parameter count of the returned operator does not necessarily equal to <paramref name="pc" />.</remarks>
|
||||
protected abstract PdtOperator GetOperator(string name, int pc);
|
||||
bool _failure;
|
||||
unsafe void Operate(PdtOperator op, int pc, bool noset = false) {
|
||||
fixed (byte* pmem = _mem) {
|
||||
op.Begin(this);
|
||||
for (int i = 0; i < pc; i++) {
|
||||
var frame = _stack[--_framecount];
|
||||
op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length));
|
||||
_goffset -= frame.Length;
|
||||
}
|
||||
op.Call(pmem + _goffset, noset);
|
||||
}
|
||||
}
|
||||
internal unsafe PdtVariableMemory StackAlloc(int type, byte* ptr, int len) {
|
||||
fixed (StackFrame* frame = &_stack[_framecount++]) {
|
||||
frame->Type = type;
|
||||
frame->Offset = _goffset;
|
||||
frame->Length = len;
|
||||
_goffset += len;
|
||||
return new PdtVariableMemory(type, ptr, len);
|
||||
}
|
||||
}
|
||||
internal void DiscardStack() {
|
||||
_goffset -= _stack[--_framecount].Length;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user