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
|
internal interface IIndexable
|
||||||
{
|
{
|
||||||
LuaType Get(Diagnostics diagnostics, TextSpan span, string s, EvaluationScope scope);
|
LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope);
|
||||||
void Set(Diagnostics diagnostics, TextSpan span, string s, LuaType value);
|
void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface IScopeOwner
|
internal interface IScopeOwner
|
||||||
|
|
|
@ -84,13 +84,27 @@ namespace Upsilon.BaseTypes
|
||||||
return Value;
|
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());
|
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();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,9 @@ namespace Upsilon.BaseTypes
|
||||||
return typeof(Dictionary<string, object>);
|
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))
|
if (EvaluationScope.TryGet(s, out var o))
|
||||||
{
|
{
|
||||||
return o;
|
return o;
|
||||||
|
@ -37,8 +38,9 @@ namespace Upsilon.BaseTypes
|
||||||
return new LuaNull();
|
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);
|
EvaluationScope.Set(new VariableSymbol(s, value.Type, false), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
using System.Collections;
|
||||||
using Upsilon.BaseTypes.Number;
|
using Upsilon.BaseTypes.Number;
|
||||||
|
using Upsilon.BaseTypes.UserData;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes
|
namespace Upsilon.BaseTypes
|
||||||
{
|
{
|
||||||
|
@ -23,8 +25,21 @@ namespace Upsilon.BaseTypes
|
||||||
case null:
|
case null:
|
||||||
return new LuaNull();
|
return new LuaNull();
|
||||||
default:
|
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
|
namespace Upsilon.BaseTypes.UserData
|
||||||
{
|
{
|
||||||
internal class UserData : LuaType, IIndexable
|
internal class GenericUserData : LuaType, IUserData
|
||||||
{
|
{
|
||||||
public UserData(object o)
|
public GenericUserData(object dictionary)
|
||||||
{
|
{
|
||||||
Value = o;
|
Value = dictionary;
|
||||||
_typeInfo = UserDataTypeHandler.GetTypeInfo(o.GetType());
|
_typeInfo = UserDataTypeHandler.GetTypeInfo(dictionary.GetType());
|
||||||
}
|
}
|
||||||
public override Type Type => Type.UserData;
|
public override Type Type => Type.UserData;
|
||||||
|
|
||||||
private object Value { get; }
|
protected virtual object Value { get; }
|
||||||
private readonly UserDataType _typeInfo;
|
private readonly UserDataType _typeInfo;
|
||||||
|
|
||||||
public override object ToCSharpObject()
|
public override object ToCSharpObject()
|
||||||
|
@ -25,8 +25,9 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
return Value.GetType();
|
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);
|
var (type, failed, error) = _typeInfo.Get(Value, s);
|
||||||
if (failed)
|
if (failed)
|
||||||
{
|
{
|
||||||
|
@ -35,8 +36,9 @@ namespace Upsilon.BaseTypes.UserData
|
||||||
return type;
|
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);
|
var (failed, error) = _typeInfo.Set(Value, s, value);
|
||||||
if (failed)
|
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);
|
return -((Number)operand);
|
||||||
else if (operand.Type == Type.UserData)
|
else if (operand.Type == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = (UserData) operand;
|
var ud = (GenericUserData) operand;
|
||||||
var (type, failed) = ud.UnaryOperator(operand, OperatorType.UnaryNegation);
|
var (type, failed) = ud.UnaryOperator(operand, OperatorType.UnaryNegation);
|
||||||
if (failed) goto default;
|
if (failed) goto default;
|
||||||
return type;
|
return type;
|
||||||
|
@ -180,7 +180,7 @@ namespace Upsilon.Evaluator
|
||||||
return !(LuaBoolean) operand;
|
return !(LuaBoolean) operand;
|
||||||
else if (operand.Type == Type.UserData)
|
else if (operand.Type == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = (UserData) operand;
|
var ud = (GenericUserData) operand;
|
||||||
var (type, failed) = ud.UnaryOperator(operand, OperatorType.LogicalNot);
|
var (type, failed) = ud.UnaryOperator(operand, OperatorType.LogicalNot);
|
||||||
if (failed) goto default;
|
if (failed) goto default;
|
||||||
return type;
|
return type;
|
||||||
|
@ -207,7 +207,7 @@ namespace Upsilon.Evaluator
|
||||||
}
|
}
|
||||||
else if (left.Type == Type.UserData)
|
else if (left.Type == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = (UserData) left;
|
var ud = (GenericUserData) left;
|
||||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Addition, right);
|
var (type, failed) = ud.BinaryOperator(left, OperatorType.Addition, right);
|
||||||
if (failed) goto default;
|
if (failed) goto default;
|
||||||
return type;
|
return type;
|
||||||
|
@ -220,7 +220,7 @@ namespace Upsilon.Evaluator
|
||||||
}
|
}
|
||||||
else if (left.Type == Type.UserData)
|
else if (left.Type == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = (UserData) left;
|
var ud = (GenericUserData) left;
|
||||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Subtraction, right);
|
var (type, failed) = ud.BinaryOperator(left, OperatorType.Subtraction, right);
|
||||||
if (failed) goto default;
|
if (failed) goto default;
|
||||||
return type;
|
return type;
|
||||||
|
@ -233,7 +233,7 @@ namespace Upsilon.Evaluator
|
||||||
}
|
}
|
||||||
else if (left.Type == Type.UserData)
|
else if (left.Type == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = (UserData) left;
|
var ud = (GenericUserData) left;
|
||||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Multiplication, right);
|
var (type, failed) = ud.BinaryOperator(left, OperatorType.Multiplication, right);
|
||||||
if (failed) goto default;
|
if (failed) goto default;
|
||||||
return type;
|
return type;
|
||||||
|
@ -246,7 +246,7 @@ namespace Upsilon.Evaluator
|
||||||
}
|
}
|
||||||
else if (left.Type == Type.UserData)
|
else if (left.Type == Type.UserData)
|
||||||
{
|
{
|
||||||
var ud = (UserData) left;
|
var ud = (GenericUserData) left;
|
||||||
var (type, failed) = ud.BinaryOperator(left, OperatorType.Division, right);
|
var (type, failed) = ud.BinaryOperator(left, OperatorType.Division, right);
|
||||||
if (failed) goto default;
|
if (failed) goto default;
|
||||||
return type;
|
return type;
|
||||||
|
@ -406,7 +406,7 @@ namespace Upsilon.Evaluator
|
||||||
scope = scopeOwner.EvaluationScope;
|
scope = scopeOwner.EvaluationScope;
|
||||||
}
|
}
|
||||||
var indexer = EvaluateExpression(e.Index);
|
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)
|
private LuaType EvaluateFullStopIndexExpression(BoundFullStopIndexExpression e)
|
||||||
{
|
{
|
||||||
|
@ -422,7 +422,7 @@ namespace Upsilon.Evaluator
|
||||||
scope = scopeOwner.EvaluationScope;
|
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)
|
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
|
||||||
|
@ -445,7 +445,7 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
throw new Exception("Cant assign to that");
|
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