Special UserData types for ILists(includes arrays) and IDictionaries
This commit is contained in:
parent
1d24be85d6
commit
105c40bc05
|
@ -5,8 +5,8 @@ namespace Upsilon.BaseTypes
|
|||
{
|
||||
internal interface IIndexable
|
||||
{
|
||||
LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope);
|
||||
void Set(Diagnostics diagnostics, TextSpan span, string s, LuaType value);
|
||||
LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope);
|
||||
void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value);
|
||||
}
|
||||
|
||||
internal interface IScopeOwner
|
||||
|
|
|
@ -84,13 +84,27 @@ namespace Upsilon.BaseTypes
|
|||
return Value;
|
||||
}
|
||||
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope)
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope)
|
||||
{
|
||||
var i = int.Parse(s);
|
||||
int i;
|
||||
if (index.Type == Type.String)
|
||||
{
|
||||
var str = (LuaString)index;
|
||||
i = int.Parse(str.Value);
|
||||
}
|
||||
else if (index.Type == Type.Number)
|
||||
{
|
||||
var ind = (Number.NumberLong) index;
|
||||
i = (int) ind.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new LuaString(Value[i - 1].ToString());
|
||||
}
|
||||
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, string s, LuaType value)
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
|
|
@ -27,8 +27,9 @@ namespace Upsilon.BaseTypes
|
|||
return typeof(Dictionary<string, object>);
|
||||
}
|
||||
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope)
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope)
|
||||
{
|
||||
var s = index.ToString();
|
||||
if (EvaluationScope.TryGet(s, out var o))
|
||||
{
|
||||
return o;
|
||||
|
@ -37,8 +38,9 @@ namespace Upsilon.BaseTypes
|
|||
return new LuaNull();
|
||||
}
|
||||
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, string s, LuaType value)
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value)
|
||||
{
|
||||
var s = index.ToString();
|
||||
EvaluationScope.Set(new VariableSymbol(s, value.Type, false), value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.Collections;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.BaseTypes.UserData;
|
||||
|
||||
namespace Upsilon.BaseTypes
|
||||
{
|
||||
|
@ -23,8 +25,21 @@ namespace Upsilon.BaseTypes
|
|||
case null:
|
||||
return new LuaNull();
|
||||
default:
|
||||
return new UserData.UserData(o);
|
||||
}
|
||||
return ConvertUserData(o);
|
||||
}
|
||||
}
|
||||
|
||||
private static LuaType ConvertUserData(object o)
|
||||
{
|
||||
if (o is IList ls)
|
||||
{
|
||||
return new ListUserData(ls);
|
||||
}
|
||||
if (o is IDictionary dic)
|
||||
{
|
||||
return new DictionaryUserData(dic);
|
||||
}
|
||||
return new GenericUserData(o);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using System.Collections;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
internal class DictionaryUserData : LuaType, IUserData
|
||||
{
|
||||
public IDictionary Dictionary { get; }
|
||||
|
||||
public DictionaryUserData(IDictionary dictionary)
|
||||
{
|
||||
Dictionary = dictionary;
|
||||
}
|
||||
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope)
|
||||
{
|
||||
var key = index.ToCSharpObject();
|
||||
if (Dictionary.Contains(key))
|
||||
{
|
||||
return Dictionary[key].ToLuaType();
|
||||
}
|
||||
//TODO: log error
|
||||
return new LuaNull();
|
||||
}
|
||||
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value)
|
||||
{
|
||||
var key = index.ToCSharpObject();
|
||||
if (Dictionary.Contains(key))
|
||||
{
|
||||
Dictionary[key] = value.ToCSharpObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
Dictionary.Add(key, value.ToCSharpObject());
|
||||
}
|
||||
}
|
||||
|
||||
public override Type Type => Type.UserData;
|
||||
public override object ToCSharpObject()
|
||||
{
|
||||
return Dictionary;
|
||||
}
|
||||
|
||||
public override System.Type GetCSharpType()
|
||||
{
|
||||
return Dictionary.GetType();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,16 +3,16 @@ using Upsilon.Text;
|
|||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
internal class UserData : LuaType, IIndexable
|
||||
internal class GenericUserData : LuaType, IUserData
|
||||
{
|
||||
public UserData(object o)
|
||||
public GenericUserData(object dictionary)
|
||||
{
|
||||
Value = o;
|
||||
_typeInfo = UserDataTypeHandler.GetTypeInfo(o.GetType());
|
||||
Value = dictionary;
|
||||
_typeInfo = UserDataTypeHandler.GetTypeInfo(dictionary.GetType());
|
||||
}
|
||||
public override Type Type => Type.UserData;
|
||||
|
||||
private object Value { get; }
|
||||
protected virtual object Value { get; }
|
||||
private readonly UserDataType _typeInfo;
|
||||
|
||||
public override object ToCSharpObject()
|
||||
|
@ -25,8 +25,9 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return Value.GetType();
|
||||
}
|
||||
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope)
|
||||
public virtual LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope)
|
||||
{
|
||||
var s = index.ToCSharpObject().ToString();
|
||||
var (type, failed, error) = _typeInfo.Get(Value, s);
|
||||
if (failed)
|
||||
{
|
||||
|
@ -35,8 +36,9 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return type;
|
||||
}
|
||||
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, string s, LuaType value)
|
||||
public virtual void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value)
|
||||
{
|
||||
var s = index.ToCSharpObject().ToString();
|
||||
var (failed, error) = _typeInfo.Set(Value, s, value);
|
||||
if (failed)
|
||||
{
|
|
@ -0,0 +1,9 @@
|
|||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
internal interface IUserData : IIndexable
|
||||
{
|
||||
object ToCSharpObject();
|
||||
System.Type GetCSharpType();
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System.Collections;
|
||||
using Upsilon.Evaluator;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
internal class ListUserData : LuaType, IUserData
|
||||
{
|
||||
private IList List { get; }
|
||||
|
||||
public ListUserData(IList list)
|
||||
{
|
||||
List = list;
|
||||
}
|
||||
|
||||
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope)
|
||||
{
|
||||
int i;
|
||||
if (index.Type == Type.String)
|
||||
{
|
||||
var str = (LuaString)index;
|
||||
i = int.Parse(str.Value) - 1;
|
||||
}
|
||||
else if (index.Type == Type.Number)
|
||||
{
|
||||
var ind = (Number.NumberLong) index;
|
||||
i = (int) ind.Value - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return List[i].ToLuaType();
|
||||
}
|
||||
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public override Type Type => Type.UserData;
|
||||
public override object ToCSharpObject()
|
||||
{
|
||||
return List;
|
||||
}
|
||||
|
||||
public override System.Type GetCSharpType()
|
||||
{
|
||||
return List.GetType();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -169,7 +169,7 @@ namespace Upsilon.Evaluator
|
|||
return -((Number)operand);
|
||||
else if (operand.Type == Type.UserData)
|
||||
{
|
||||
var ud = (UserData) operand;
|
||||
var ud = (GenericUserData) operand;
|
||||
var (type, failed) = ud.UnaryOperator(operand, OperatorType.UnaryNegation);
|
||||
if (failed) goto default;
|
||||
return type;
|
||||
|
@ -180,7 +180,7 @@ namespace Upsilon.Evaluator
|
|||
return !(LuaBoolean) operand;
|
||||
else if (operand.Type == Type.UserData)
|
||||
{
|
||||
var ud = (UserData) operand;
|
||||
var ud = (GenericUserData) operand;
|
||||
var (type, failed) = ud.UnaryOperator(operand, OperatorType.LogicalNot);
|
||||
if (failed) goto default;
|
||||
return type;
|
||||
|
@ -207,7 +207,7 @@ namespace Upsilon.Evaluator
|
|||
}
|
||||
else if (left.Type == Type.UserData)
|
||||
{
|
||||
var ud = (UserData) left;
|
||||
var ud = (GenericUserData) left;
|
||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Addition, right);
|
||||
if (failed) goto default;
|
||||
return type;
|
||||
|
@ -220,7 +220,7 @@ namespace Upsilon.Evaluator
|
|||
}
|
||||
else if (left.Type == Type.UserData)
|
||||
{
|
||||
var ud = (UserData) left;
|
||||
var ud = (GenericUserData) left;
|
||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Subtraction, right);
|
||||
if (failed) goto default;
|
||||
return type;
|
||||
|
@ -233,7 +233,7 @@ namespace Upsilon.Evaluator
|
|||
}
|
||||
else if (left.Type == Type.UserData)
|
||||
{
|
||||
var ud = (UserData) left;
|
||||
var ud = (GenericUserData) left;
|
||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Multiplication, right);
|
||||
if (failed) goto default;
|
||||
return type;
|
||||
|
@ -246,7 +246,7 @@ namespace Upsilon.Evaluator
|
|||
}
|
||||
else if (left.Type == Type.UserData)
|
||||
{
|
||||
var ud = (UserData) left;
|
||||
var ud = (GenericUserData) left;
|
||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Division, right);
|
||||
if (failed) goto default;
|
||||
return type;
|
||||
|
@ -406,7 +406,7 @@ namespace Upsilon.Evaluator
|
|||
scope = scopeOwner.EvaluationScope;
|
||||
}
|
||||
var indexer = EvaluateExpression(e.Index);
|
||||
return indexable.Get(_diagnostics, e.Span, indexer.ToString(), scope);
|
||||
return indexable.Get(_diagnostics, e.Span, indexer, scope);
|
||||
}
|
||||
private LuaType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e)
|
||||
{
|
||||
|
@ -422,7 +422,7 @@ namespace Upsilon.Evaluator
|
|||
scope = scopeOwner.EvaluationScope;
|
||||
}
|
||||
|
||||
return indexable.Get(_diagnostics, e.Span, e.Index, scope);
|
||||
return indexable.Get(_diagnostics, e.Span, e.Index.ToLuaType(), scope);
|
||||
}
|
||||
|
||||
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
|
||||
|
@ -445,7 +445,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
throw new Exception("Cant assign to that");
|
||||
}
|
||||
indexable.Set(_diagnostics, e.Span, index.ToString(), value);
|
||||
indexable.Set(_diagnostics, e.Span, index.ToString().ToLuaType(), value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using System.Collections.Generic;
|
||||
using Upsilon.Evaluator;
|
||||
using Xunit;
|
||||
|
||||
namespace UpsilonTests
|
||||
{
|
||||
public class UserDataDictionaryTests
|
||||
{
|
||||
[Fact]
|
||||
public void BasicStringKeyed()
|
||||
{
|
||||
var arr = new Dictionary<string, int>
|
||||
{
|
||||
{"test", 100},
|
||||
{"1234", 90},
|
||||
{"here", 1683},
|
||||
};
|
||||
const string input = @"
|
||||
function getValue(arr)
|
||||
return arr[""here""]
|
||||
end
|
||||
";
|
||||
var script = new Script(input);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var evaluated = script.EvaluateFunction<long>("getValue", new[] {arr});
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(1683, evaluated);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System.Collections.Generic;
|
||||
using Upsilon.Evaluator;
|
||||
using Xunit;
|
||||
|
||||
namespace UpsilonTests
|
||||
{
|
||||
public class UserDataListTests
|
||||
{
|
||||
[Fact]
|
||||
public void BasicArrayTest()
|
||||
{
|
||||
var arr = new[] {100, 30, 56, 213, 76787};
|
||||
const string input = @"
|
||||
function getValue(arr)
|
||||
return arr[3]
|
||||
end
|
||||
";
|
||||
var script = new Script(input);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var evaluated = script.EvaluateFunction<long>("getValue", new[] {arr});
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(56, evaluated);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BasicListTest()
|
||||
{
|
||||
var arr = new List<int> {100, 30, 56, 213, 76787};
|
||||
const string input = @"
|
||||
function getValue(arr)
|
||||
return arr[2]
|
||||
end
|
||||
";
|
||||
var script = new Script(input);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var evaluated = script.EvaluateFunction<long>("getValue", new[] {arr});
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(30, evaluated);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue