Special UserData types for ILists(includes arrays) and IDictionaries

This commit is contained in:
Deukhoofd 2018-11-21 14:49:59 +01:00
parent 1d24be85d6
commit 105c40bc05
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
11 changed files with 242 additions and 24 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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)
{

View File

@ -0,0 +1,9 @@
namespace Upsilon.BaseTypes.UserData
{
internal interface IUserData : IIndexable
{
object ToCSharpObject();
System.Type GetCSharpType();
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}