ProjectDDD/Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/Lua/Lua Interpreter/LuaValue/LuaTable.cs

557 lines
15 KiB (Stored with Git LFS)
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Language.Lua
{
public class LuaTable : LuaValue
{
private List<LuaValue> list;
private Dictionary<LuaValue, LuaValue> dict;
//[PixelCrushers] Cache key values for faster lookup:
private Dictionary<int, LuaValue> m_intKeyCache = new Dictionary<int, LuaValue>();
private Dictionary<string, LuaValue> m_stringKeyCache = new Dictionary<string, LuaValue>();
public LuaTable() { }
public LuaTable(LuaTable parent)
{
this.MetaTable = new LuaTable();
this.MetaTable.SetNameValue("__index", parent);
this.MetaTable.SetNameValue("__newindex", parent);
}
public LuaTable MetaTable { get; set; }
public override object Value
{
get { return this; }
}
public override string GetTypeCode()
{
return "table";
}
public int Length
{
get
{
if (this.list == null)
{
return 0;
}
else
{
return this.list.Count;
}
}
}
public int Count
{
get
{
if (this.dict == null)
{
return 0;
}
else
{
return this.dict.Count;
}
}
}
public override string ToString()
{
if (this.MetaTable != null)
{
LuaFunction function = this.MetaTable.GetValue("__tostring") as LuaFunction;
if (function != null)
{
return function.Invoke(new LuaValue[] { this }).ToString();
}
}
return "Table " + this.GetHashCode();
}
public List<LuaValue> List //[PixelCrushers]
{
get
{
if (this.list == null) this.list = new List<LuaValue>();
return this.list;
}
}
public Dictionary<LuaValue, LuaValue> Dict //[PixelCrushers]
{
get
{
if (this.dict == null) this.dict = new Dictionary<LuaValue, LuaValue>();
return this.dict;
}
}
public void AddRaw(string key, LuaValue value) //[PixelCrushers]
{
if (m_stringKeyCache.ContainsKey(key))
{
var keyValue = m_stringKeyCache[key];
Dict[keyValue] = value;
}
else
{
var keyValue = new LuaString(key);
Dict[keyValue] = value;
m_stringKeyCache[key] = keyValue;
}
}
public void AddRaw(int key, LuaValue value) //[PixelCrushers]
{
if (m_intKeyCache.ContainsKey(key))
{
var keyValue = m_intKeyCache[key];
Dict[keyValue] = value;
}
else if (key == this.Length + 1)
{
this.AddValue(value);
}
else if (key > 0 && key <= this.Length)
{
this.list[key - 1] = value;
}
else
{
var keyValue = new LuaNumber(key);
Dict[keyValue] = value;
m_intKeyCache[key] = keyValue;
}
}
public IEnumerable<LuaValue> ListValues
{
get { return this.list; }
}
public IEnumerable<LuaValue> Keys
{
get
{
if (this.Length > 0)
{
for (int index = 1; index <= this.list.Count; index++)
{
yield return new LuaNumber(index);
}
}
if (this.Count > 0)
{
foreach (LuaValue key in this.dict.Keys)
{
yield return key;
}
}
}
}
public IEnumerable<KeyValuePair<LuaValue, LuaValue>> KeyValuePairs
{
get { return this.dict; }
}
public bool ContainsKey(LuaValue key)
{
if (this.dict != null)
{
if (this.dict.ContainsKey(key))
{
return true;
}
}
if (this.list != null)
{
LuaNumber index = key as LuaNumber;
if (index != null && index.Number == (int)index.Number)
{
return index.Number >= 1 && index.Number <= this.list.Count;
}
}
return false;
}
public void AddValue(LuaValue value)
{
if (this.list == null)
{
this.list = new List<LuaValue>();
}
this.list.Add(value);
}
public void InsertValue(int index, LuaValue value)
{
if (index > 0 && index <= this.Length + 1)
{
this.list.Insert(index - 1, value);
}
else
{
throw new ArgumentOutOfRangeException("index");
}
}
public bool Remove(LuaValue item)
{
return this.list.Remove(item);
}
public void RemoveAt(int index)
{
this.list.RemoveAt(index - 1);
}
public void Sort()
{
this.list.Sort((a, b) =>
{
LuaNumber n = a as LuaNumber;
LuaNumber m = b as LuaNumber;
if (n != null && m != null)
{
return n.Number.CompareTo(m.Number);
}
LuaString s = a as LuaString;
LuaString t = b as LuaString;
if (s != null && t != null)
{
return s.Text.CompareTo(t.Text);
}
return 0;
});
}
public void Sort(LuaFunction compare)
{
this.list.Sort((a, b) =>
{
LuaValue result = compare.Invoke(new LuaValue[] { a, b });
LuaBoolean boolValue = result as LuaBoolean;
if (boolValue != null && boolValue.BoolValue == true)
{
return 1;
}
else
{
return -1;
}
});
}
public LuaValue GetValue(int index)
{
if (index > 0 && index <= this.Length)
{
return this.list[index - 1];
}
//[PixelCrushers]
if (dict != null)
{
if (m_intKeyCache.ContainsKey(index) && dict.ContainsKey(m_intKeyCache[index])) return dict[m_intKeyCache[index]];
return GetValue(index.ToString());
}
return LuaNil.Nil;
}
public LuaValue GetValue(string name)
{
LuaValue key = this.GetKey(name);
if (key == LuaNil.Nil)
{
if (this.MetaTable != null)
{
return this.GetValueFromMetaTable(name);
}
return LuaNil.Nil;
}
else
{
return this.dict[key];
}
}
public LuaValue GetKey(string key)
{
if (this.dict == null) return LuaNil.Nil;
if (m_stringKeyCache.ContainsKey(key)) return m_stringKeyCache[key];
foreach (LuaValue value in this.dict.Keys)
{
//[PixelCrushers]
//LuaString str = value as LuaString;
//if (str != null && string.Equals(str.Text, key, StringComparison.Ordinal))
//{
// return value;
//}
//LuaString str = value as LuaString;
if (value != null && string.Equals(value.ToString(), key, StringComparison.Ordinal))
{
return value;
}
}
return LuaNil.Nil;
}
public void SetNameValue(string name, LuaValue value)
{
if (value == LuaNil.Nil)
{
this.RemoveKey(name);
}
else
{
this.RawSetValue(name, value);
}
}
private void RemoveKey(string name)
{
LuaValue key = this.GetKey(name);
if (key != LuaNil.Nil)
{
this.dict.Remove(key);
}
m_stringKeyCache.Remove(name);
}
public void SetKeyValue(LuaValue key, LuaValue value)
{
LuaNumber number = key as LuaNumber;
if (number != null && number.Number == (int)number.Number)
{
int index = (int)number.Number;
if (m_intKeyCache.ContainsKey(index) && Dict.ContainsKey(m_intKeyCache[index])) //[PixelCrushers]
{
Dict[m_intKeyCache[index]] = value;
return;
}
if (index == this.Length + 1)
{
this.AddValue(value);
return;
}
if (index > 0 && index <= this.Length)
{
this.list[index - 1] = value;
return;
}
}
if (value == LuaNil.Nil)
{
this.RemoveKey(key);
return;
}
if (this.dict == null)
{
this.dict = new Dictionary<LuaValue, LuaValue>();
}
this.dict[key] = value;
//[PixelCrushers] Update caches:
int intValue;
if (GetIntValue(key, out intValue))
{
m_intKeyCache[intValue] = key;
}
else if (key is LuaString)
{
m_stringKeyCache[(key as LuaString).Text] = key;
}
}
private bool GetIntValue(LuaValue value, out int intValue)
{
var number = value as LuaNumber;
if (number != null && number.Number == (int)number.Number)
{
intValue = (int)number.Number;
return true;
}
intValue = 0;
return false;
}
private void RemoveKey(LuaValue key)
{
if (key != LuaNil.Nil && this.dict != null && this.dict.ContainsKey(key))
{
this.dict.Remove(key);
}
//[PixelCrushers] Update caches:
int intValue;
if (GetIntValue(key, out intValue))
{
m_intKeyCache.Remove(intValue);
}
else if (key is LuaString)
{
m_stringKeyCache.Remove((key as LuaString).Text);
}
}
public LuaValue GetValue(LuaValue key)
{
if (key == LuaNil.Nil)
{
return LuaNil.Nil;
}
else
{
LuaNumber number = key as LuaNumber;
if (number != null && number.Number == (int)number.Number)
{
int index = (int)number.Number;
if (index > 0 && index <= this.Length)
{
return this.list[index - 1];
}
}
if (this.dict != null && this.dict.ContainsKey(key))
{
return this.dict[key];
}
if (this.MetaTable != null)
{
return this.GetValueFromMetaTable(key);
}
return LuaNil.Nil;
}
}
private LuaValue GetValueFromMetaTable(string name)
{
LuaValue indexer = this.MetaTable.GetValue("__index");
LuaTable table = indexer as LuaTable;
if (table != null)
{
return table.GetValue(name);
}
LuaFunction function = indexer as LuaFunction;
if (function != null)
{
return function.Function.Invoke(new LuaValue[] { new LuaString(name) });
}
return LuaNil.Nil;
}
private LuaValue GetValueFromMetaTable(LuaValue key)
{
LuaValue indexer = this.MetaTable.GetValue("__index");
LuaTable table = indexer as LuaTable;
if (table != null)
{
return table.GetValue(key);
}
LuaFunction function = indexer as LuaFunction;
if (function != null)
{
return function.Function.Invoke(new LuaValue[] { key });
}
return LuaNil.Nil;
}
public LuaFunction Register(string name, LuaFunc function)
{
LuaFunction luaFunc = new LuaFunction(function);
this.SetNameValue(name, luaFunc);
return luaFunc;
}
/// <summary>
/// [PixelCrushers] Registers a C# method by its MethodInfo.
/// </summary>
/// <returns>The Lua function instance wrapping the method.</returns>
/// <param name="name">Name of the function in Lua.</param>
/// <param name="target">Target object containing the method (or <c>null</c>).</param>
/// <param name="methodInfo">Method info.</param>
public LuaFunction RegisterMethodFunction(string name, object target, System.Reflection.MethodInfo methodInfo)
{
LuaMethodFunction luaFunc = new LuaMethodFunction(target, methodInfo);
this.SetNameValue(name, luaFunc);
return luaFunc;
}
public LuaValue RawGetValue(LuaValue key)
{
if (this.dict != null && this.dict.ContainsKey(key))
{
return this.dict[key];
}
return LuaNil.Nil;
}
public void RawSetValue(string name, LuaValue value)
{
LuaValue key = this.GetKey(name);
if (key == LuaNil.Nil)
{
key = new LuaString(name);
m_stringKeyCache[name] = key; //[PixelCrushers]
}
if (this.dict == null)
{
this.dict = new Dictionary<LuaValue, LuaValue>();
}
this.dict[key] = value;
}
}
}