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;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs.meta
Normal file
11
Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e91dc9e4fd28a584c8f2fce4f9e9b648
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
247
Assets/Cryville/Common/Pdt/PdtExpression.cs
Normal file
247
Assets/Cryville/Common/Pdt/PdtExpression.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// PDT expression.
|
||||
/// </summary>
|
||||
public class PdtExpression {
|
||||
internal LinkedList<PdtInstruction> Instructions;
|
||||
/// <summary>
|
||||
/// Whether the value of this expression is constant.
|
||||
/// </summary>
|
||||
/// <remarks>The value of this property is <c>false</c> until it is optimized.</remarks>
|
||||
public bool IsConstant { get; internal set; }
|
||||
internal bool IsPotentialConstant;
|
||||
internal PdtExpression(LinkedList<PdtInstruction> ins) {
|
||||
Instructions = ins;
|
||||
}
|
||||
public override string ToString() {
|
||||
string r = "";
|
||||
bool flag = false;
|
||||
foreach (PdtInstruction ins in Instructions) {
|
||||
if (flag) r += "; ";
|
||||
r += ins.ToString();
|
||||
flag = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
internal abstract class PdtInstruction {
|
||||
internal abstract void Execute(PdtEvaluatorBase etor);
|
||||
public class PushConstant : PdtInstruction {
|
||||
public int Type { get; private set; }
|
||||
public byte[] Value { get; private set; }
|
||||
public PushConstant(int type, byte[] value) {
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
public PushConstant(int type, byte[] buffer, int offset, int len) {
|
||||
Type = type;
|
||||
Value = new byte[len];
|
||||
Array.Copy(buffer, offset, Value, 0, len);
|
||||
}
|
||||
internal override void Execute(PdtEvaluatorBase etor) {
|
||||
etor.PushConstant(Type, Value);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("pushc ({0:x8}){1}", Type, BitConverter.ToString(Value));
|
||||
}
|
||||
}
|
||||
public class PushVariable : PdtInstruction {
|
||||
private string m_name;
|
||||
public string Name { get { return m_name; } }
|
||||
public PushVariable(string name) {
|
||||
m_name = name;
|
||||
}
|
||||
internal override void Execute(PdtEvaluatorBase etor) {
|
||||
etor.PushVariable(ref m_name);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("pushv {0}", Name);
|
||||
}
|
||||
}
|
||||
public class Operate : PdtInstruction {
|
||||
private string m_name;
|
||||
public string Name { get { return m_name; } }
|
||||
public int ParamCount { get; private set; }
|
||||
public Operate(string name, int paramCount) {
|
||||
m_name = name;
|
||||
ParamCount = paramCount;
|
||||
}
|
||||
internal override void Execute(PdtEvaluatorBase etor) {
|
||||
etor.Operate(ref m_name, ParamCount);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("op {0}({1})", Name, ParamCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
public partial class PdtInterpreter<T> {
|
||||
readonly static Dictionary<char, int> pri = new Dictionary<char, int> {
|
||||
{ '*', 5 }, { '/', 5 }, { '%', 5 },
|
||||
{ '+', 4 }, { '-', 4 },
|
||||
{ '=', 3 }, { '<', 3 }, { '>', 3 },
|
||||
{ '&', 2 },
|
||||
{ '|', 1 }, { '!', 1 },
|
||||
{ ',', 0 },
|
||||
};
|
||||
|
||||
readonly static PdtExpression _emptyexp;
|
||||
static PdtInterpreter() {
|
||||
var ins = new LinkedList<PdtInstruction>();
|
||||
ins.AddLast(new PdtInstruction.PushConstant(
|
||||
PdtInternalType.Number, BitConverter.GetBytes(1f)
|
||||
));
|
||||
_emptyexp = new PdtExpression(ins);
|
||||
}
|
||||
|
||||
PdtExpToken GetToken() {
|
||||
ws();
|
||||
var result = new PdtExpToken {
|
||||
Type = ct & 0x0fe0
|
||||
};
|
||||
switch (result.Type) {
|
||||
case 0x0020: result.Value = GetIdentifier(); break;
|
||||
case 0x0040: result.Value = GetNumber(); break;
|
||||
case 0x0100: result.Value = GetString(); break;
|
||||
default: result.Value = cc.ToString(); Position++; break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private struct PdtExpToken {
|
||||
public int Type { get; set; }
|
||||
public string Value { get; set; }
|
||||
public override string ToString() {
|
||||
return string.Format("0x{0:x4}: {1}", Type, Value);
|
||||
}
|
||||
public readonly static PdtExpToken EmptyOperator = new PdtExpToken {
|
||||
Type = 0x0080,
|
||||
Value = "",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets an expression from the current position and loads it onto an instruction set.
|
||||
/// </summary>
|
||||
/// <param name="ins">The instruction set.</param>
|
||||
/// <param name="enc">
|
||||
/// <para>The enclosing scope type of the (sub)expression. May be one of the following:</para>
|
||||
/// <list type="bullet">
|
||||
/// <item><term><c>-2</c></term><description>The expression is in a root scope which ends at a semicolon.</description></item>
|
||||
/// <item><term><c>-1</c></term><description>The expression is in a bracketed scope which ends at a closing parenthesis.</description></item>
|
||||
/// <item><term>Any non-negative values</term><description>The expression is in an auxiliary scope which ends before a closing parenthesis or an operator whose priority is lower (less) than the value of this parameter.</description></item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
/// <param name="pc">The parameter count in this (sub)expression.</param>
|
||||
/// <param name="token">The token already parsed but required for the interpretation of the subexpression.</param>
|
||||
/// <returns>The expression token following this (sub)expression.</returns>
|
||||
PdtExpToken InterpretExp(LinkedList<PdtInstruction> ins, int enc, out int pc, PdtExpToken? token = null) {
|
||||
PdtExpToken t1, t2;
|
||||
int insc0 = ins.Count;
|
||||
pc = 1;
|
||||
if (token == null) t1 = PdtExpToken.EmptyOperator;
|
||||
else t1 = token.Value;
|
||||
while (true) {
|
||||
t2 = InterpretExpBlock(ins);
|
||||
panic:
|
||||
switch (t2.Type) {
|
||||
case 0x0080:
|
||||
if (t1.Value != "") {
|
||||
int p1 = pri[t1.Value[0]];
|
||||
int p2 = pri[t2.Value[0]];
|
||||
if (p2 <= enc) goto exit;
|
||||
if (p2 > p1) {
|
||||
int _;
|
||||
t2 = InterpretExp(ins, p1, out _, t2);
|
||||
goto panic;
|
||||
}
|
||||
if (t1.Value != ",") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2));
|
||||
else pc++;
|
||||
}
|
||||
t1 = t2;
|
||||
break;
|
||||
case 0x0400:
|
||||
if (enc == -2) throw new FormatException("Expression not enclosed correctly: Too many closing brackets");
|
||||
if (ins.Count == insc0) pc = 0;
|
||||
goto exit;
|
||||
case 0x0800:
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
if (t1.Value != "," && t1.Value != "") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2));
|
||||
else if (t1.Value == ",") pc++;
|
||||
return t2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets an expression block which consists of several adjacent constants and subexpressions, optionally with a unary operator.
|
||||
/// </summary>
|
||||
/// <param name="ins">The instruction set.</param>
|
||||
/// <returns>The expression token following this expression block.</returns>
|
||||
PdtExpToken InterpretExpBlock(LinkedList<PdtInstruction> ins) {
|
||||
var t = GetToken();
|
||||
if (t.Type == 0x0080) {
|
||||
var r = InterpretExpBlock(ins);
|
||||
ins.AddLast(new PdtInstruction.Operate(t.Value, 1));
|
||||
return r;
|
||||
}
|
||||
bool flag = false;
|
||||
PdtExpToken? buf = null;
|
||||
while (true) {
|
||||
if (buf != null && t.Type != 0x0200) {
|
||||
PdtExpression def;
|
||||
if (defs.TryGetValue(buf.Value.Value, out def)) {
|
||||
foreach (var i in def.Instructions) ins.AddLast(i);
|
||||
}
|
||||
else ins.AddLast(new PdtInstruction.PushVariable(buf.Value.Value));
|
||||
buf = null;
|
||||
TryPushAdjMul(ins, ref flag);
|
||||
}
|
||||
switch (t.Type) {
|
||||
case 0x0020:
|
||||
buf = t;
|
||||
break;
|
||||
case 0x0040:
|
||||
float num = float.Parse(t.Value);
|
||||
ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.Number, BitConverter.GetBytes(num)));
|
||||
break;
|
||||
case 0x0100:
|
||||
int strlen = t.Value.Length;
|
||||
unsafe {
|
||||
var strbuf = new byte[strlen * sizeof(char) + sizeof(int)];
|
||||
fixed (byte* psuffix = strbuf) {
|
||||
*(int*)psuffix = strlen;
|
||||
}
|
||||
Encoding.Unicode.GetBytes(t.Value, 0, strlen, strbuf, sizeof(int));
|
||||
ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.String, strbuf));
|
||||
}
|
||||
break;
|
||||
case 0x0200:
|
||||
int pc;
|
||||
InterpretExp(ins, -1, out pc);
|
||||
if (buf != null) {
|
||||
ins.AddLast(new PdtInstruction.Operate(buf.Value.Value, pc));
|
||||
buf = null;
|
||||
}
|
||||
else if (pc > 1) {
|
||||
ins.AddLast(new PdtInstruction.Operate(",", pc));
|
||||
}
|
||||
else if (pc == 0)
|
||||
throw new FormatException("Empty subexpression");
|
||||
break;
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
if (buf == null) TryPushAdjMul(ins, ref flag);
|
||||
t = GetToken();
|
||||
}
|
||||
}
|
||||
void TryPushAdjMul(LinkedList<PdtInstruction> ins, ref bool flag) {
|
||||
if (flag) ins.AddLast(new PdtInstruction.Operate("*", 2));
|
||||
else flag = true;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Common/Pdt/PdtExpression.cs.meta
Normal file
11
Assets/Cryville/Common/Pdt/PdtExpression.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a551104b532c8d0469917e3e0e8c2cba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
28
Assets/Cryville/Common/Pdt/PdtInternalType.cs
Normal file
28
Assets/Cryville/Common/Pdt/PdtInternalType.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// The identifiers of the internal types of PDT.
|
||||
/// </summary>
|
||||
public static class PdtInternalType {
|
||||
internal readonly static int Error = "error".GetHashCode();
|
||||
/// <summary>
|
||||
/// Array of a same variable-length type, with a suffix indicating the element count and the element type.
|
||||
/// </summary>
|
||||
public readonly static int Array = "array".GetHashCode();
|
||||
/// <summary>
|
||||
/// IEEE 754 32-bit floating-point number.
|
||||
/// </summary>
|
||||
public readonly static int Number = "number".GetHashCode();
|
||||
/// <summary>
|
||||
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units.
|
||||
/// </summary>
|
||||
public readonly static int String = "string".GetHashCode();
|
||||
/// <summary>
|
||||
/// A sequence of UTF-16 code units representing the name of an undefined variable.
|
||||
/// </summary>
|
||||
public readonly static int Undefined = "undefined".GetHashCode();
|
||||
/// <summary>
|
||||
/// Vector of a same constant-length type, with a suffix indicating the element type.
|
||||
/// </summary>
|
||||
public readonly static int Vector = "vector".GetHashCode();
|
||||
}
|
||||
}
|
11
Assets/Cryville/Common/Pdt/PdtInternalType.cs.meta
Normal file
11
Assets/Cryville/Common/Pdt/PdtInternalType.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36eb4aecae64aff4891c4ddd2d1ff68c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
232
Assets/Cryville/Common/Pdt/PdtInterpreter.cs
Normal file
232
Assets/Cryville/Common/Pdt/PdtInterpreter.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// Interpreter for Property Definition Tree (PDT) file format.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object type represented by the PDT.</typeparam>
|
||||
public partial class PdtInterpreter<T> {
|
||||
/// <summary>
|
||||
/// The character category map.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <list type="bullet">
|
||||
/// <item><term><c>0x0001</c></term><description>White Space</description></item>
|
||||
/// <item><term><c>0x0010</c></term><description>Identifier</description></item>
|
||||
/// <item><term><c>0x0020</c></term><description>Identifier Begin</description></item>
|
||||
/// <item><term><c>0x0040</c></term><description>Digit</description></item>
|
||||
/// <item><term><c>0x0080</c></term><description>Operator</description></item>
|
||||
/// <item><term><c>0x0100</c></term><description>String</description></item>
|
||||
/// <item><term><c>0x0200</c></term><description>Opening Bracket</description></item>
|
||||
/// <item><term><c>0x0400</c></term><description>Closing Bracket</description></item>
|
||||
/// <item><term><c>0x0800</c></term><description>End of Expression</description></item>
|
||||
/// <item><term><c>0x1000</c></term><description>End of Key</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
readonly static int[] cm = new int[] {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080,
|
||||
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0000,
|
||||
0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
|
||||
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0030,
|
||||
0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
|
||||
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0000, 0x0000,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interprets a source string to an object of type <typeparamref name="T" />.
|
||||
/// </summary>
|
||||
/// <param name="src">The source string.</param>
|
||||
/// <returns>The interpreted object.</returns>
|
||||
public static T Interpret(string src) {
|
||||
return Interpret(src, BinderAttribute.CreateBinderOfType(typeof(T)));
|
||||
}
|
||||
/// <summary>
|
||||
/// Interprets a source string to an object of type <typeparamref name="T" /> with a binder.
|
||||
/// </summary>
|
||||
/// <param name="src">The source string.</param>
|
||||
/// <param name="binder">The binder.</param>
|
||||
/// <returns>The interpreted object.</returns>
|
||||
public static T Interpret(string src, Binder binder) {
|
||||
return new PdtInterpreter<T>(src, binder).Interpret();
|
||||
}
|
||||
|
||||
readonly string _src;
|
||||
readonly Binder _binder;
|
||||
protected int Position { get; private set; }
|
||||
#pragma warning disable IDE1006
|
||||
protected char cc { get { return _src[Position]; } }
|
||||
protected int ct { get { return cm[cc]; } }
|
||||
protected string tokenb(int flag) { // Token Whitelist
|
||||
int sp = Position;
|
||||
while ((ct & flag) == 0) Position++;
|
||||
return _src.Substring(sp, Position - sp);
|
||||
}
|
||||
protected string tokenw(int flag) { // Token Whitelist
|
||||
int sp = Position;
|
||||
while ((ct & flag) != 0) Position++;
|
||||
return _src.Substring(sp, Position - sp);
|
||||
}
|
||||
protected void ws() {
|
||||
while ((ct & 0x0001) != 0) Position++;
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
|
||||
protected char GetChar() {
|
||||
char r = cc;
|
||||
Position++;
|
||||
return r;
|
||||
}
|
||||
protected string GetIdentifier() {
|
||||
if ((ct & 0x0020) == 0) return "";
|
||||
return tokenw(0x0010);
|
||||
}
|
||||
protected string GetNumber() {
|
||||
return tokenw(0x0040);
|
||||
}
|
||||
protected string GetString() {
|
||||
int sp = Position;
|
||||
do {
|
||||
if (cc == '\\') Position++;
|
||||
Position++;
|
||||
} while (ct != 0x0100);
|
||||
Position++;
|
||||
return Regex.Replace(_src.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1");
|
||||
}
|
||||
protected PdtExpression GetExp() {
|
||||
var ins = new LinkedList<PdtInstruction>();
|
||||
int _;
|
||||
InterpretExp(ins, -2, out _);
|
||||
return new PdtExpression(ins);
|
||||
}
|
||||
|
||||
readonly Dictionary<string, PdtExpression> defs = new Dictionary<string, PdtExpression>();
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="PdtInterpreter{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="src">The source string.</param>
|
||||
/// <param name="binder">The binder. May be <c>null</c>.</param>
|
||||
public PdtInterpreter(string src, Binder binder) {
|
||||
_src = src;
|
||||
_binder = binder;
|
||||
if (_binder == null)
|
||||
_binder = BinderAttribute.CreateBinderOfType(typeof(T));
|
||||
}
|
||||
/// <summary>
|
||||
/// Interprets the source to an object of type <typeparamref name="T" />.
|
||||
/// </summary>
|
||||
/// <returns>The interpreted object.</returns>
|
||||
public T Interpret() {
|
||||
InterpretDirectives();
|
||||
return (T)InterpretObject(typeof(T));
|
||||
}
|
||||
void InterpretDirectives() {
|
||||
bool flag = false;
|
||||
ws();
|
||||
while (cc == '#') {
|
||||
Position++;
|
||||
switch (GetIdentifier()) {
|
||||
case "ver":
|
||||
ws();
|
||||
Logger.Log("main", 3, "PDT", "Legacy PDT directive #ver={0} found. Ignoring.", GetNumber());
|
||||
break;
|
||||
case "format":
|
||||
ws();
|
||||
if (GetNumber() != "1")
|
||||
throw new NotSupportedException("Format not supported");
|
||||
flag = true;
|
||||
break;
|
||||
case "define":
|
||||
if (!flag) throw new FormatException("Format directive not found");
|
||||
ws();
|
||||
string dname = GetIdentifier();
|
||||
ws();
|
||||
PdtExpression dexp = GetExp();
|
||||
defs.Add(dname, dexp);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported directive found");
|
||||
}
|
||||
ws();
|
||||
}
|
||||
if (!flag) throw new FormatException("Format directive not found");
|
||||
}
|
||||
object InterpretObject(Type type) {
|
||||
var result = ReflectionHelper.InvokeEmptyConstructor(type);
|
||||
bool dictflag = ReflectionHelper.IsGenericDictionary(type);
|
||||
while (true) {
|
||||
try { ws(); }
|
||||
catch (IndexOutOfRangeException) { return result; }
|
||||
object pkey = InterpretKey(type);
|
||||
char c = GetChar();
|
||||
switch (c) {
|
||||
case '{':
|
||||
if (dictflag) {
|
||||
var ktype = type.GetGenericArguments()[0];
|
||||
var ptype = type.GetGenericArguments()[1];
|
||||
object key = _binder.ChangeType(pkey, ktype, null);
|
||||
object value = InterpretObject(ptype);
|
||||
((IDictionary)result).Add(key, value);
|
||||
}
|
||||
else {
|
||||
MemberInfo prop;
|
||||
bool flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
|
||||
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
|
||||
Type ptype = ReflectionHelper.GetMemberType(prop);
|
||||
if (ReflectionHelper.IsGenericDictionary(ptype)) {
|
||||
var ktype = ptype.GetGenericArguments()[0];
|
||||
var vtype = ptype.GetGenericArguments()[1];
|
||||
if (flag) {
|
||||
object key = _binder.ChangeType(pkey, ktype, null);
|
||||
object value = InterpretObject(vtype);
|
||||
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
|
||||
}
|
||||
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
|
||||
}
|
||||
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
case ';':
|
||||
var exp = c == ';' ? _emptyexp : GetExp();
|
||||
if (dictflag) {
|
||||
var ktype = type.GetGenericArguments()[0];
|
||||
var vtype = type.GetGenericArguments()[1];
|
||||
object key = _binder.ChangeType(pkey, ktype, null);
|
||||
object value = _binder.ChangeType(exp, vtype, null);
|
||||
((IDictionary)result).Add(key, value);
|
||||
}
|
||||
else {
|
||||
MemberInfo prop;
|
||||
bool flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
|
||||
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
|
||||
var ptype = ReflectionHelper.GetMemberType(prop);
|
||||
if (!typeof(IDictionary).IsAssignableFrom(ptype)) {
|
||||
object value = _binder.ChangeType(exp, ptype, null);
|
||||
ReflectionHelper.SetValue(prop, result, value, _binder);
|
||||
}
|
||||
else {
|
||||
var ktype = ptype.GetGenericArguments()[0];
|
||||
var vtype = ptype.GetGenericArguments()[1];
|
||||
object key = _binder.ChangeType(pkey, ktype, null);
|
||||
object value = _binder.ChangeType(exp, vtype, null);
|
||||
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected virtual object InterpretKey(Type type) {
|
||||
return tokenb(0x1000).Trim();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Common/Pdt/PdtInterpreter.cs.meta
Normal file
11
Assets/Cryville/Common/Pdt/PdtInterpreter.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a66a8564bee7c8449417a795cee8729
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
77
Assets/Cryville/Common/Pdt/PdtOperator.cs
Normal file
77
Assets/Cryville/Common/Pdt/PdtOperator.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// PDT operator.
|
||||
/// </summary>
|
||||
public unsafe abstract class PdtOperator {
|
||||
byte* _prmem;
|
||||
int _loadindex;
|
||||
readonly PdtVariableMemory[] _operands;
|
||||
/// <summary>
|
||||
/// The count of the operands loaded.
|
||||
/// </summary>
|
||||
protected int LoadedOperandCount { get { return ParamCount - _loadindex; } }
|
||||
/// <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 IndexOutOfRangeException();
|
||||
int i = index + _loadindex;
|
||||
return _operands[i];
|
||||
}
|
||||
internal int ParamCount { get; private set; }
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="PdtOperator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="pc">The suggested parameter count.</param>
|
||||
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");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Executes the operator.
|
||||
/// </summary>
|
||||
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) {
|
||||
_failure = true;
|
||||
throw new InvalidOperationException("Return frame already requested");
|
||||
}
|
||||
_rfreq = true;
|
||||
return _etor.StackAlloc(type, _prmem, len);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Common/Pdt/PdtOperator.cs.meta
Normal file
11
Assets/Cryville/Common/Pdt/PdtOperator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc184c2d84fe5ea449cea78cba46d74d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
749
Assets/Cryville/Common/Pdt/PdtReader.cs
Normal file
749
Assets/Cryville/Common/Pdt/PdtReader.cs
Normal file
@@ -0,0 +1,749 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
#if false
|
||||
[Obsolete]
|
||||
public static class PdtReader {
|
||||
readonly static char[] ws = {
|
||||
' ', '\t', '\n', '\r'
|
||||
};
|
||||
readonly static char[] spunc = {
|
||||
' ', '\t', '\n', '\r',
|
||||
'{', '}', ';'
|
||||
};
|
||||
readonly static char[] ipunc = {
|
||||
' ', '\t', '\n', '\r',
|
||||
'{', '}', ';',
|
||||
':'
|
||||
};
|
||||
readonly static char[] vpunc = {
|
||||
'{', '}', ';'
|
||||
};
|
||||
static int pos;
|
||||
static string data;
|
||||
static char cc {
|
||||
get {
|
||||
return data[pos];
|
||||
}
|
||||
}
|
||||
static bool eof {
|
||||
get {
|
||||
return pos == data.Length;
|
||||
}
|
||||
}
|
||||
static Dictionary<string, Expression> definitions;
|
||||
public static T Read<T>(string _data, Binder binder = null) {
|
||||
data = _data;
|
||||
pos = 0;
|
||||
definitions = new Dictionary<string, Expression>();
|
||||
while (true) {
|
||||
if (cc == '#') {
|
||||
SkipChar();
|
||||
var s = GetIdentifier();
|
||||
switch (s) {
|
||||
case "ver":
|
||||
var s2 = GetString();
|
||||
if (s2 != "1") throw new FormatException("Invalid PDT version");
|
||||
continue;
|
||||
case "define":
|
||||
var s3 = GetString();
|
||||
var s4 = GetValue();
|
||||
definitions.Add(s3, new Expression(s4, definitions));
|
||||
SkipChar();
|
||||
// TODO
|
||||
continue;
|
||||
default:
|
||||
SkipLine();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (binder == null)
|
||||
binder = BinderAttribute.CreateBinderOfType(typeof(T));
|
||||
return (T)ParseObject(typeof(T), binder);
|
||||
}
|
||||
|
||||
static object ParseObject(Type type, Binder binder) {
|
||||
// TODO Binder
|
||||
object obj = type.GetConstructor(new Type[]{}).Invoke(new object[]{});
|
||||
while (true) {
|
||||
if (eof) return obj;
|
||||
string str = GetValue();
|
||||
if (cc == '{') { // List item
|
||||
SkipChar();
|
||||
string strkey = str;
|
||||
if (typeof(IDictionary).IsAssignableFrom(type)) {
|
||||
var ktype = type.GetGenericArguments()[0];
|
||||
var ptype = type.GetGenericArguments()[1];
|
||||
object key = binder.ChangeType(strkey, ktype, null);
|
||||
object value = ParseObject(ptype, binder);
|
||||
((IDictionary)obj).Add(key, value);
|
||||
}
|
||||
else {
|
||||
MemberInfo prop = null;
|
||||
Type ttype = null;
|
||||
bool flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
|
||||
if (!flag)
|
||||
prop = ReflectionHelper.GetMember(type, strkey);
|
||||
ttype = ReflectionHelper.GetMemberType(prop);
|
||||
if (!typeof(IDictionary).IsAssignableFrom(ttype)) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else {
|
||||
var ktype = ttype.GetGenericArguments()[0];
|
||||
var ptype = ttype.GetGenericArguments()[1];
|
||||
if (flag) {
|
||||
object key = binder.ChangeType(strkey, ktype, null);
|
||||
object value = ParseObject(ptype, binder);
|
||||
((IDictionary)ReflectionHelper.GetValue(prop, obj)).Add(key, value);
|
||||
}
|
||||
else {
|
||||
ReflectionHelper.SetValue(prop, obj, ParseObject(ttype, binder));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cc == ';') { // Single property
|
||||
SkipChar();
|
||||
string strkey;
|
||||
MemberInfo prop = null;
|
||||
if (str[0] == '*') { // Component-like property
|
||||
strkey = str.Substring(1);
|
||||
prop = ReflectionHelper.FindMemberWithAttribute<ComponentListAttribute>(type);
|
||||
var ttype = ReflectionHelper.GetMemberType(prop);
|
||||
if (!typeof(IList).IsAssignableFrom(ttype))
|
||||
throw new Exception(); // TODO
|
||||
var ktype = ttype.GetGenericArguments()[0];
|
||||
object key = binder.ChangeType(strkey, ktype, null);
|
||||
((IList)ReflectionHelper.GetValue(prop, obj)).Add(key);
|
||||
}
|
||||
else { // Common property
|
||||
var kv = str.Split(new char[]{':'}, 2);
|
||||
strkey = kv[0];
|
||||
// TODO
|
||||
if (typeof(IDictionary).IsAssignableFrom(type)) {
|
||||
var ktype = type.GetGenericArguments()[0];
|
||||
var ptype = type.GetGenericArguments()[1];
|
||||
object key = binder.ChangeType(strkey, ktype, null);
|
||||
object value = binder.ChangeType(new Expression(
|
||||
kv.Length == 1 ? "true" : kv[1], definitions
|
||||
), ptype, null);
|
||||
((IDictionary)obj).Add(key, value);
|
||||
}
|
||||
else {
|
||||
bool flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
|
||||
if (!flag)
|
||||
prop = ReflectionHelper.GetMember(type, strkey);
|
||||
var ttype = ReflectionHelper.GetMemberType(prop);
|
||||
if (!typeof(IDictionary).IsAssignableFrom(ttype)) {
|
||||
object value = binder.ChangeType(new Expression(
|
||||
kv.Length == 1 ? "true" : kv[1], definitions
|
||||
), ttype, null);
|
||||
ReflectionHelper.SetValue(prop, obj, value, binder);
|
||||
}
|
||||
else {
|
||||
var ktype = ttype.GetGenericArguments()[0];
|
||||
var ptype = ttype.GetGenericArguments()[1];
|
||||
object key = binder.ChangeType(strkey, ktype, null);
|
||||
object value = binder.ChangeType(new Expression(
|
||||
kv.Length == 1 ? "true" : kv[1], definitions
|
||||
), ptype, null);
|
||||
((IDictionary)ReflectionHelper.GetValue(prop, obj)).Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cc == '}') {
|
||||
try { SkipChar(); }
|
||||
catch (IndexOutOfRangeException) { }
|
||||
return obj;
|
||||
}
|
||||
else throw new Exception(); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
static void SkipChar() {
|
||||
pos++;
|
||||
SkipWs();
|
||||
}
|
||||
|
||||
static void SkipWs() {
|
||||
while (true) {
|
||||
for (; ws.Contains(cc); pos++);
|
||||
if (data[pos] == '/' && data[pos + 1] == '*') {
|
||||
for (; data[pos] != '*' || data[pos+1] != '/'; pos++);
|
||||
pos += 2;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
}
|
||||
|
||||
static string GetIdentifier() {
|
||||
SkipWs();
|
||||
string r = "";
|
||||
for (; !ipunc.Contains(cc); pos++) r += cc;
|
||||
SkipWs();
|
||||
return r;
|
||||
}
|
||||
|
||||
static string GetString() {
|
||||
SkipWs();
|
||||
string r = "";
|
||||
for (; !spunc.Contains(cc); pos++) r += cc;
|
||||
SkipWs();
|
||||
return r;
|
||||
}
|
||||
|
||||
static string GetValue() {
|
||||
SkipWs();
|
||||
string r = "";
|
||||
for (; !vpunc.Contains(cc); pos++) r += cc;
|
||||
SkipWs();
|
||||
return r.Trim();
|
||||
}
|
||||
|
||||
static void SkipLine() {
|
||||
for (; cc != '\n'; pos++);
|
||||
SkipWs();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public class ElementListAttribute : Attribute { }
|
||||
public class ComponentListAttribute : Attribute { }
|
||||
public class PropertyListAttribute : Attribute { }
|
||||
|
||||
#if false
|
||||
[Obsolete]
|
||||
public abstract class ExpBase {
|
||||
public string exp {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public ExpBase(string s) {
|
||||
exp = s;
|
||||
}
|
||||
public override string ToString() {
|
||||
return exp;
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public abstract class ValueBase : ExpBase {
|
||||
public ValueBase(string s) : base(s) { }
|
||||
|
||||
object preEvalResult;
|
||||
byte preEvalDepth = 0;
|
||||
public bool IsDynamic {
|
||||
get { return preEvalDepth == 0; }
|
||||
}
|
||||
|
||||
protected abstract object EvalInternal(IEvaluator etor);
|
||||
public void PreEval(IEvaluator etor, byte depth = 1) {
|
||||
if (depth == 0) throw new ArgumentException("depth cannot be 0");
|
||||
if (preEvalDepth != 0 && preEvalDepth < depth) return;
|
||||
try {
|
||||
preEvalResult = PreEvalInternal(etor, depth);
|
||||
preEvalDepth = depth;
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
protected virtual object PreEvalInternal(IEvaluator etor, byte depth) {
|
||||
return Eval(etor);
|
||||
}
|
||||
public object Eval(IEvaluator etor) {
|
||||
if (preEvalDepth != 0)
|
||||
return preEvalResult;
|
||||
return EvalInternal(etor);
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public class Identifier : ValueBase {
|
||||
public Identifier(string s) : base(s) { }
|
||||
protected override object EvalInternal(IEvaluator etor) {
|
||||
return etor.EvalIdentifier(exp);
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public class Operand : ExpBase {
|
||||
public OperandPriority Priority {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public Operand(string s) : base(s) {
|
||||
switch (s) {
|
||||
case ".": Priority = OperandPriority.Prop; break;
|
||||
case "*": case "/": Priority = OperandPriority.Mul; break;
|
||||
case "+": case "-": Priority = OperandPriority.Add; break;
|
||||
case " ": case ",": Priority = OperandPriority.Sep; break;
|
||||
default: Priority = OperandPriority.None; break;
|
||||
}
|
||||
}
|
||||
public Operand(string s, OperandPriority p) : base(s) {
|
||||
Priority = p;
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public enum OperandPriority {
|
||||
None = 0,
|
||||
Prop = 5,
|
||||
NeibMul = 4,
|
||||
Mul = 3,
|
||||
Add = 2,
|
||||
Sep = 1
|
||||
}
|
||||
[Obsolete]
|
||||
public abstract class ConstantBase : ValueBase {
|
||||
public ConstantBase(string s) : base(s) { }
|
||||
}
|
||||
[Obsolete]
|
||||
public class CNumber : ConstantBase {
|
||||
public CNumber(string s) : base(s) { }
|
||||
protected override object EvalInternal(IEvaluator etor) {
|
||||
return etor.ParseNumber(exp);
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public class CString : ConstantBase {
|
||||
public CString(string s) : base(s) { }
|
||||
protected override object EvalInternal(IEvaluator etor) {
|
||||
return etor.ParseString(exp);
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public class BracketInitial : ExpBase {
|
||||
public BracketInitial() : base("(") { }
|
||||
}
|
||||
[Obsolete]
|
||||
public class BracketFinal : ExpBase {
|
||||
public BracketFinal() : base(")") { }
|
||||
}
|
||||
[Obsolete]
|
||||
public class Expression : ValueBase {
|
||||
List<ValueBase> estack = new List<ValueBase>();
|
||||
List<Operand> ostack = new List<Operand>();
|
||||
StackType type;
|
||||
enum StackType {
|
||||
Root, Unary, Bracketed, Supportive, Function
|
||||
}
|
||||
|
||||
readonly OperandPriority Priority;
|
||||
public Expression(string s, Dictionary<string, Expression> def) : base("") {
|
||||
var exp = s.Trim();
|
||||
type = StackType.Root;
|
||||
int pos = 0;
|
||||
var b = new List<ExpBase>();
|
||||
while (pos < exp.Length) {
|
||||
b.Add(Forward(ref exp, ref pos));
|
||||
}
|
||||
var lb = b[b.Count - 1];
|
||||
if (def.ContainsKey(lb.exp)) {
|
||||
b.Add(def[lb.exp]);
|
||||
b.Remove(lb);
|
||||
}
|
||||
for (int i = b.Count - 2; i >= 0; i--) {
|
||||
// TODO Insertion
|
||||
var lhb = b[i];
|
||||
var rhb = b[i + 1];
|
||||
if (lhb is ConstantBase || lhb is Expression || lhb is BracketFinal) {
|
||||
if (rhb is Identifier || rhb is Expression || rhb is BracketInitial) {
|
||||
b.Insert(i + 1, new Operand("*", OperandPriority.NeibMul));
|
||||
}
|
||||
}
|
||||
else if (lhb is Identifier) {
|
||||
if (rhb is Expression) {
|
||||
b.Insert(i + 1, new Operand("*", OperandPriority.NeibMul));
|
||||
}
|
||||
if (def.ContainsKey(lhb.exp)) {
|
||||
b.Insert(i, def[lhb.exp]);
|
||||
b.Remove(lhb);
|
||||
}
|
||||
}
|
||||
}
|
||||
int p = 0;
|
||||
estack.Add(new Expression(b, ref p, StackType.Bracketed, def));
|
||||
}
|
||||
|
||||
public Expression Clone() {
|
||||
var r = (Expression)this.MemberwiseClone();
|
||||
|
||||
var es = new ValueBase[estack.Count];
|
||||
estack.CopyTo(es);
|
||||
r.estack = es.ToList();
|
||||
|
||||
var os = new Operand[ostack.Count];
|
||||
ostack.CopyTo(os);
|
||||
r.ostack = os.ToList();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Expression(List<ExpBase> b, ref int p, StackType t, Dictionary<string, Expression> def) : base("") {
|
||||
type = t;
|
||||
if (t == StackType.Unary) {
|
||||
ostack.Add((Operand)b[p]);
|
||||
p++;
|
||||
}
|
||||
while (p < b.Count - 1) {
|
||||
if (estack.Count == 0) {
|
||||
var b0 = b[p];
|
||||
if (b0 is Operand) {
|
||||
var lp = p;
|
||||
var e = new Expression(
|
||||
b,
|
||||
ref p,
|
||||
StackType.Unary,
|
||||
def
|
||||
);
|
||||
b.Insert(p, e);
|
||||
b.RemoveRange(lp, p - lp);
|
||||
p = lp;
|
||||
}
|
||||
else if (b0 is BracketInitial) {
|
||||
var lp = p;
|
||||
p++;
|
||||
var e = new Expression(
|
||||
b,
|
||||
ref p,
|
||||
StackType.Bracketed,
|
||||
def
|
||||
);
|
||||
b.Insert(p, e);
|
||||
b.RemoveRange(lp, p - lp);
|
||||
p = lp;
|
||||
}
|
||||
estack.Add((ValueBase)b[p]);
|
||||
p++;
|
||||
if (t == StackType.Unary) {
|
||||
if (estack.Count != 1)
|
||||
throw new Exception(); // TODO
|
||||
else return;
|
||||
}
|
||||
}
|
||||
if (p >= b.Count) return;
|
||||
var b1 = b[p];
|
||||
if (b1 is BracketFinal) {
|
||||
if (t == StackType.Bracketed) p++;
|
||||
return;
|
||||
}
|
||||
var b2 = b[p + 1];
|
||||
if (b2 is BracketInitial) {
|
||||
var lp = p + 1;
|
||||
p += 2;
|
||||
var e = new Expression(
|
||||
b,
|
||||
ref p,
|
||||
StackType.Bracketed,
|
||||
def
|
||||
);
|
||||
b.Insert(p, e);
|
||||
b.RemoveRange(lp, p - lp);
|
||||
p = lp - 1;
|
||||
b2 = b[p + 1];
|
||||
}
|
||||
if (b1 is Operand) {
|
||||
if (estack.Count == 1)
|
||||
Priority = ((Operand)b1).Priority;
|
||||
if (b2 is Operand) {
|
||||
var lp = p + 1;
|
||||
p++;
|
||||
var e = new Expression(
|
||||
b,
|
||||
ref p,
|
||||
StackType.Unary,
|
||||
def
|
||||
);
|
||||
b.Insert(p, e);
|
||||
b.RemoveRange(lp, p - lp);
|
||||
p = lp - 1;
|
||||
b2 = b[p + 1];
|
||||
}
|
||||
if (p + 2 >= b.Count) {
|
||||
ostack.Add((Operand)b1);
|
||||
estack.Add((ValueBase)b2);
|
||||
p += 2;
|
||||
return;
|
||||
}
|
||||
var b3 = b[p + 2];
|
||||
if (b3 is BracketFinal) {
|
||||
ostack.Add((Operand)b1);
|
||||
estack.Add((ValueBase)b2);
|
||||
p += 2;
|
||||
if (t == StackType.Bracketed) p++;
|
||||
return;
|
||||
}
|
||||
else if (b3 is Operand) {
|
||||
var o1 = (Operand)b1; var o2 = (Operand)b3;
|
||||
if (o2.Priority == Priority) {
|
||||
ostack.Add(o1); estack.Add((ValueBase)b2);
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
else if (o2.Priority > Priority) {
|
||||
var lp = p + 1;
|
||||
p++;
|
||||
var e = new Expression(
|
||||
b, ref p,
|
||||
StackType.Supportive, def
|
||||
);
|
||||
b.Insert(p, e);
|
||||
b.RemoveRange(lp, p - lp);
|
||||
p = lp - 1;
|
||||
continue;
|
||||
}
|
||||
else if (o2.Priority < Priority) {
|
||||
ostack.Add(o1);
|
||||
estack.Add((ValueBase)b2);
|
||||
// b.RemoveRange(0, 2);
|
||||
if (type == StackType.Bracketed) {
|
||||
Expression cl = this.Clone();
|
||||
cl.type = StackType.Supportive;
|
||||
estack.Clear();
|
||||
ostack.Clear();
|
||||
estack.Add(cl);
|
||||
Priority = o2.Priority;
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
type = StackType.Supportive;
|
||||
p += 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new Exception(); // TODO
|
||||
}
|
||||
else
|
||||
throw new Exception(); // TODO
|
||||
throw new Exception(); // TODO
|
||||
|
||||
/*if (lb is Identifier) {
|
||||
if (def.ContainsKey(lb.exp)) {
|
||||
b.Add(def[lb.exp]);
|
||||
b.Remove(lb);
|
||||
}
|
||||
}
|
||||
// Unary
|
||||
if (estack.Count == 0) {
|
||||
if (b[0] is Operand) {
|
||||
b.Add(new Expression(
|
||||
b,
|
||||
ref p,
|
||||
StackType.Unary,
|
||||
def
|
||||
));
|
||||
b.RemoveAt(0);
|
||||
}
|
||||
if (b[0] is ValueBase) {
|
||||
estack.Add((ValueBase)b[0]);
|
||||
b.RemoveAt(0);
|
||||
if (type == StackType.Unary) return;
|
||||
if (b.Count == 0) continue;
|
||||
}
|
||||
}
|
||||
if (estack.Count == 1) {
|
||||
if (b[0] is Operand)
|
||||
Priority = ((Operand)b[0]).Priority;
|
||||
}
|
||||
// Bracket
|
||||
if (lb is BracketInitial) {
|
||||
b.Remove(lb);
|
||||
b.Add(new Expression(b, ref p, StackType.Bracketed, def));
|
||||
}
|
||||
else if (lb is BracketFinal) {
|
||||
if (type != StackType.Bracketed) p--;
|
||||
foreach (var i in b) {
|
||||
if (i is Operand) ostack.Add((Operand)i);
|
||||
else if (i is BracketFinal) return;
|
||||
else estack.Add((ValueBase)i);
|
||||
}
|
||||
}
|
||||
var c = b.Count;
|
||||
if (c <= 1) continue;
|
||||
// Two blocks
|
||||
lb = b[c - 1];
|
||||
var lb1 = b[c - 2];
|
||||
if (lb is Operand && lb1 is Operand) {
|
||||
b.Add(new Expression(
|
||||
b,
|
||||
ref p,
|
||||
StackType.Unary,
|
||||
def
|
||||
));
|
||||
b.RemoveAt(b.Count - 2);
|
||||
}
|
||||
c = b.Count;
|
||||
if (c <= 2) continue;
|
||||
// Three blocks
|
||||
var b0 = b[0];
|
||||
var b1 = b[1];
|
||||
var b2 = b[2];
|
||||
if (!(b0 is Operand))
|
||||
throw new Exception(); // TODO
|
||||
if (!(b1 is ValueBase))
|
||||
throw new Exception(); // TODO
|
||||
if (!(b2 is Operand))
|
||||
throw new Exception(); // TODO
|
||||
var o1 = (Operand)b0; var o2 = (Operand)b2;
|
||||
if (o2.Priority == Priority) {
|
||||
ostack.Add(o1); estack.Add((ValueBase)b1);
|
||||
b.Remove(o1); b.Remove(b1);
|
||||
continue;
|
||||
}
|
||||
if (o2.Priority > Priority) {
|
||||
b.Add(new Expression(
|
||||
b, ref p,
|
||||
StackType.Supportive, def
|
||||
));
|
||||
b.RemoveRange(1, b.Count - 2);
|
||||
continue;
|
||||
}
|
||||
if (o2.Priority < Priority) {
|
||||
ostack.Add(o1);
|
||||
estack.Add((ValueBase)b1);
|
||||
b.RemoveRange(0, 2);
|
||||
if (type == StackType.Bracketed) {
|
||||
Expression cl = this.Clone();
|
||||
cl.type = StackType.Supportive;
|
||||
estack.Clear();
|
||||
ostack.Clear();
|
||||
estack.Add(cl);
|
||||
Priority = o2.Priority;
|
||||
}
|
||||
else {
|
||||
type = StackType.Supportive;
|
||||
// p = o2.Index;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
estack.Add((ValueBase)b[b.Count - 1]);
|
||||
p++;
|
||||
}
|
||||
ExpBase Forward(ref string s, ref int p) {
|
||||
char sc = s[p];
|
||||
string r = "";
|
||||
if (cat(sc) == 3) {
|
||||
p++;
|
||||
return new BracketInitial();
|
||||
}
|
||||
else if (cat(sc) == 4) {
|
||||
p++;
|
||||
return new BracketFinal();
|
||||
}
|
||||
else if (cat(sc) == 5) {
|
||||
for (; p < s.Length; p++) {
|
||||
if (cat(s[p]) != 5) break;
|
||||
r += s[p];
|
||||
}
|
||||
if (r == ".") return new Operand(r);
|
||||
else return new CNumber(r);
|
||||
}
|
||||
else if (cat(sc) == 2) {
|
||||
p++;
|
||||
for (; s[p] != sc; p++)
|
||||
r += s[p];
|
||||
p++;
|
||||
return new CString(r);
|
||||
}
|
||||
else if (cat(sc) == 0) {
|
||||
for (; p < s.Length; p++) {
|
||||
if (cat(s[p]) != 0) break;
|
||||
r += s[p];
|
||||
}
|
||||
if (p == s.Length) return new Identifier(r);
|
||||
if (s[p] == '(') return new Operand(r);
|
||||
else return new Identifier(r);
|
||||
}
|
||||
else if (cat(sc) == 1) {
|
||||
p++;
|
||||
return new Operand(sc.ToString());
|
||||
}
|
||||
else
|
||||
throw new Exception(); // TODO
|
||||
}
|
||||
|
||||
protected override object EvalInternal(IEvaluator etor) {
|
||||
if (type == StackType.Unary) {
|
||||
if (ostack[0].Priority == OperandPriority.None)
|
||||
return etor.OperateFunction(ostack[0], estack[0].Eval(etor));
|
||||
else
|
||||
return etor.OperateUnary(ostack[0], estack[0].Eval(etor));
|
||||
}
|
||||
else {
|
||||
object r = estack[0].Eval(etor);
|
||||
for (int i = 0; i < ostack.Count; i++) {
|
||||
r = etor.OperateBinary(
|
||||
ostack[i], r, estack[i+1].Eval(etor)
|
||||
);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
public T Eval<T>(IEvaluator etor) {
|
||||
return (T)etor.Cast(typeof(T), EvalInternal(etor));
|
||||
}
|
||||
protected override object PreEvalInternal(IEvaluator etor, byte depth) {
|
||||
try { return EvalInternal(etor); }
|
||||
catch (Exception) {
|
||||
foreach (var v in estack)
|
||||
v.PreEval(etor, depth);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// 0: Other, 1: Operand, 2: String,
|
||||
// 3: SOE, 4: EOE, 5: Number
|
||||
static readonly byte[] ctl = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 1, 0, 1, 1, 2, 3, 4, 1, 1, 1, 1, 5, 1,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
|
||||
};
|
||||
static byte cat(char c) {
|
||||
if (c >> 7 != 0)
|
||||
return 0;
|
||||
else
|
||||
return ctl[c];
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
if (type == StackType.Unary)
|
||||
return string.Format("{0}{1}", ostack[0], estack[0]);
|
||||
if (type == StackType.Function)
|
||||
return string.Format("{0}{1}", ostack[0], estack[0]);
|
||||
string r = estack[0].ToString();
|
||||
for (int i = 0; i < ostack.Count; i++) {
|
||||
r += ostack[i].ToString();
|
||||
r += estack[i + 1].ToString();
|
||||
}
|
||||
if (type == StackType.Bracketed)
|
||||
r = string.Format("({0})", r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public interface IEvaluator {
|
||||
object ParseNumber(string exp);
|
||||
object ParseString(string exp);
|
||||
object EvalIdentifier(string exp);
|
||||
object OperateUnary(Operand op, object q);
|
||||
object OperateBinary(Operand op, object q, object r);
|
||||
object OperateFunction(Operand op, object q);
|
||||
// TODO [Obsolete]
|
||||
object Cast(Type type, object obj);
|
||||
//public abstract Func<Type, object, object> GetCastCallback(Type dest, Type source);
|
||||
}
|
||||
#endif
|
||||
}
|
12
Assets/Cryville/Common/Pdt/PdtReader.cs.meta
Normal file
12
Assets/Cryville/Common/Pdt/PdtReader.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 688e46fb4d8e6a041844f592f1333af7
|
||||
timeCreated: 1608801352
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
143
Assets/Cryville/Common/Pdt/PdtVariableMemory.cs
Normal file
143
Assets/Cryville/Common/Pdt/PdtVariableMemory.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// Span on the memory of a <see cref="PdtEvaluatorBase" />.
|
||||
/// </summary>
|
||||
public unsafe struct PdtVariableMemory {
|
||||
byte* _ptr;
|
||||
/// <summary>
|
||||
/// The length of the span.
|
||||
/// </summary>
|
||||
public int Length { get; private set; }
|
||||
/// <summary>
|
||||
/// The type of the span.
|
||||
/// </summary>
|
||||
public int Type { get; private set; }
|
||||
internal PdtVariableMemory(int type, byte* ptr, int len) {
|
||||
Type = type;
|
||||
_ptr = ptr;
|
||||
Length = len;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the memory in the span to a buffer.
|
||||
/// </summary>
|
||||
/// <param name="dest">The destination buffer.</param>
|
||||
/// <param name="destOffset">The offset on the destination buffer to start copying to.</param>
|
||||
public void CopyTo(byte[] dest, int destOffset) {
|
||||
fixed (byte* ptr = dest) {
|
||||
CopyTo(ptr, destOffset, Length);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the memory in the span to a buffer.
|
||||
/// </summary>
|
||||
/// <param name="dest">The destination buffer.</param>
|
||||
/// <param name="destOffset">The offset on the destination buffer to start copying to.</param>
|
||||
/// <param name="length">The length to copy.</param>
|
||||
public void CopyTo(byte* dest, int destOffset, int length) {
|
||||
for (int i = 0; i < length; i++)
|
||||
dest[destOffset + i] = _ptr[i];
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the memory of the span as a number.
|
||||
/// </summary>
|
||||
/// <returns>A number.</returns>
|
||||
/// <exception cref="InvalidCastException">The span does not represent a number.</exception>
|
||||
public float AsNumber() {
|
||||
if (Type != PdtInternalType.Number)
|
||||
throw new InvalidCastException("Not a number");
|
||||
float value;
|
||||
byte* ptr = (byte*)&value;
|
||||
for (int i = 0; i < sizeof(float); i++)
|
||||
ptr[i] = _ptr[i];
|
||||
return value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the memory of the span to a number.
|
||||
/// </summary>
|
||||
/// <param name="value">The number.</param>
|
||||
/// <exception cref="InvalidCastException">The span does not represent a number.</exception>
|
||||
public void SetNumber(float value) {
|
||||
if (Type != PdtInternalType.Number)
|
||||
throw new InvalidCastException("Not a number");
|
||||
byte* ptr = (byte*)&value;
|
||||
for (int i = 0; i < sizeof(float); i++)
|
||||
_ptr[i] = ptr[i];
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the memory of the span as a string.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset on the span to start reading from.</param>
|
||||
/// <returns>A string.</returns>
|
||||
/// <exception cref="InvalidCastException">The span at the offset does not represent a string.</exception>
|
||||
public string AsString(int offset = 0) {
|
||||
if (Type != PdtInternalType.String && Type != PdtInternalType.Array)
|
||||
throw new InvalidCastException("Not a string");
|
||||
var len = *(int*)(_ptr + offset);
|
||||
return new string((char*)(_ptr + offset + sizeof(int)), 0, len);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the memory of the span to a string.
|
||||
/// </summary>
|
||||
/// <param name="value">The string.</param>
|
||||
/// <param name="offset">The offset from the start of the span.</param>
|
||||
/// <exception cref="InvalidCastException">The span at the offset does not represent a string.</exception>
|
||||
/// <exception cref="InvalidOperationException">The length of the span is not sufficient.</exception>
|
||||
public void SetString(string value, int offset = 0) {
|
||||
if (Type != PdtInternalType.String && Type != PdtInternalType.Array)
|
||||
throw new InvalidCastException("Not a string");
|
||||
int strlen = value.Length;
|
||||
if (Length < strlen * sizeof(char) + sizeof(int) + offset)
|
||||
throw new InvalidOperationException("Frame length not sufficient");
|
||||
char* ptr = (char*)(_ptr + offset + sizeof(int));
|
||||
*(int*)(_ptr + offset) = strlen;
|
||||
int i = 0;
|
||||
foreach (var c in value) ptr[i++] = c;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the memory of the span as an undefined identifier.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset on the span to start reading from.</param>
|
||||
/// <returns>The name of an undefined identifier.</returns>
|
||||
/// <exception cref="InvalidCastException">The span does not represent an undefined identifier.</exception>
|
||||
public string AsIdentifier(int offset = 0) {
|
||||
if (Type != PdtInternalType.Undefined && Type != PdtInternalType.Array)
|
||||
throw new InvalidCastException("Not an identifier");
|
||||
var len = *(int*)(_ptr + offset);
|
||||
return new string((char*)(_ptr + offset + sizeof(int)), 0, len);
|
||||
}
|
||||
internal void* TrustedAsOfLength(int len) {
|
||||
if (Length < len)
|
||||
throw new InvalidCastException("Type not matched");
|
||||
return _ptr;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the array suffix.
|
||||
/// </summary>
|
||||
/// <param name="arrtype">The type of the array.</param>
|
||||
/// <param name="pc">The item count of the array.</param>
|
||||
/// <exception cref="InvalidCastException">The span does not represent an array.</exception>
|
||||
public void GetArraySuffix(out int arrtype, out int pc) {
|
||||
if (Type != PdtInternalType.Array && Type != PdtInternalType.Array)
|
||||
throw new InvalidCastException("Not an array or vector");
|
||||
arrtype = *(int*)(_ptr + Length - sizeof(int));
|
||||
if (Type == PdtInternalType.Array) pc = *(int*)(_ptr + Length - 2 * sizeof(int));
|
||||
else pc = -1;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the array suffix.
|
||||
/// </summary>
|
||||
/// <param name="arrtype">The type of the array.</param>
|
||||
/// <param name="pc">The item count of the array.</param>
|
||||
/// <exception cref="InvalidCastException">The span does not represent an array.</exception>
|
||||
public void SetArraySuffix(int arrtype, int pc = 0) {
|
||||
if (Type != PdtInternalType.Vector && Type != PdtInternalType.Array)
|
||||
throw new InvalidCastException("Not an array or vector");
|
||||
*(int*)(_ptr + Length - sizeof(int)) = arrtype;
|
||||
if (Type == PdtInternalType.Array) *(int*)(_ptr + Length - 2 * sizeof(int)) = pc;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Common/Pdt/PdtVariableMemory.cs.meta
Normal file
11
Assets/Cryville/Common/Pdt/PdtVariableMemory.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e710eef537a1ac488ef6bce16625b62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user