diff --git a/Upsilon/BaseTypes/IIndexable.cs b/Upsilon/BaseTypes/IIndexable.cs index 1912917..45ea7d3 100644 --- a/Upsilon/BaseTypes/IIndexable.cs +++ b/Upsilon/BaseTypes/IIndexable.cs @@ -5,6 +5,7 @@ namespace Upsilon.BaseTypes internal interface IIndexable { LuaType Get(string s, EvaluationScope scope); + void Set(string s, LuaType value); } internal interface IScopeOwner diff --git a/Upsilon/BaseTypes/LuaString.cs b/Upsilon/BaseTypes/LuaString.cs index b373da1..386c9e5 100644 --- a/Upsilon/BaseTypes/LuaString.cs +++ b/Upsilon/BaseTypes/LuaString.cs @@ -83,5 +83,10 @@ namespace Upsilon.BaseTypes var i = int.Parse(s); return new LuaString(Value[i - 1].ToString()); } + + public void Set(string s, LuaType value) + { + throw new NotSupportedException(); + } } } \ No newline at end of file diff --git a/Upsilon/BaseTypes/TypeConversion.cs b/Upsilon/BaseTypes/TypeConversion.cs index 221a2e0..5d18a2a 100644 --- a/Upsilon/BaseTypes/TypeConversion.cs +++ b/Upsilon/BaseTypes/TypeConversion.cs @@ -1,4 +1,3 @@ -using System; using Upsilon.BaseTypes.Number; namespace Upsilon.BaseTypes @@ -19,12 +18,13 @@ namespace Upsilon.BaseTypes return new NumberDouble(f); case double f: return new NumberDouble(f); - - + case string s: + return new LuaString(s); + case null: + return new LuaNull(); default: - throw new Exception(); + return new UserData.UserData(o); } - } } } \ No newline at end of file diff --git a/Upsilon/BaseTypes/UserData/UserData.cs b/Upsilon/BaseTypes/UserData/UserData.cs new file mode 100644 index 0000000..5a28bcc --- /dev/null +++ b/Upsilon/BaseTypes/UserData/UserData.cs @@ -0,0 +1,32 @@ +using Upsilon.Evaluator; + +namespace Upsilon.BaseTypes.UserData +{ + internal class UserData : LuaType, IIndexable + { + public UserData(object o) + { + Value = o; + _typeInfo = UserDataTypeHandler.GetTypeInfo(o.GetType()); + } + public override Type Type => Type.UserData; + + private object Value { get; } + private readonly UserDataType _typeInfo; + + public override object ToCSharpObject() + { + return Value; + } + + public LuaType Get(string s, EvaluationScope scope) + { + return _typeInfo.Get(Value, s); + } + + public void Set(string s, LuaType value) + { + _typeInfo.Set(Value, s, value); + } + } +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/UserData/UserDataType.cs b/Upsilon/BaseTypes/UserData/UserDataType.cs new file mode 100644 index 0000000..7b2a11f --- /dev/null +++ b/Upsilon/BaseTypes/UserData/UserDataType.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Upsilon.BaseTypes.UserData +{ + internal class UserDataType + { + public UserDataType(System.Type type) + { + Type = type; + Variables = type.GetFields().ToDictionary(x => x.Name, x => x); + Properties = type.GetProperties().ToDictionary(x => x.Name, x => x); + } + + private System.Type Type { get; } + private Dictionary Variables { get; } + private Dictionary Properties { get; } + + public LuaType Get(object value, string member) + { + if (value.GetType() != Type) + return null; + if (Variables.TryGetValue(member, out var info)) + { + return info.GetValue(value).ToLuaType(); + } + if (Properties.TryGetValue(member, out var property)) + { + return property.GetValue(value).ToLuaType(); + } + + return null; + } + + public void Set(object value, string member, LuaType newValue) + { + if (value.GetType() != Type) + return; + if (Variables.TryGetValue(member, out var info)) + { + info.SetValue(value, newValue.ToCSharpObject()); + } + if (Properties.TryGetValue(member, out var property)) + { + property.SetValue(value, newValue.ToCSharpObject()); + } + return; + } + } +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs b/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs new file mode 100644 index 0000000..ef0e111 --- /dev/null +++ b/Upsilon/BaseTypes/UserData/UserDataTypeHandler.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Upsilon.BaseTypes.UserData +{ + public static class UserDataTypeHandler + { + private static readonly Dictionary _types = new Dictionary(); + + public static void LoadType(System.Type t) + { + var info = new UserDataType(t); + _types.Add(t, info); + } + + public static void LoadType() + { + LoadType(typeof(T)); + } + + internal static UserDataType GetTypeInfo(System.Type t) + { + return _types[t]; + } + } +} \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 097cf5b..0b739af 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -355,13 +355,11 @@ namespace Upsilon.Evaluator var table = EvaluateExpression(e.TableIndexExpression.Identifier); var index = EvaluateExpression(e.TableIndexExpression.Index); var value = EvaluateExpression(e.Value); - if (table.Type != Type.Table) + if (!(table is IIndexable indexable)) { - throw new Exception("Not a table"); + throw new Exception("Cant assign to that"); } - - var t = (LuaTable) table; - t.Set(index.ToString(), value); + indexable.Set(index.ToString(), value); } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index cf0148c..8ebfcd3 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -84,7 +84,9 @@ namespace Upsilon.Evaluator public T Evaluate() { - return Convert(Evaluator.Evaluate(Bind())); + var bound = Bind(); + var evaluate = Evaluator.Evaluate(bound); + return Convert(evaluate); } public T EvaluateFunction(string functionName, object[] parameters = null) diff --git a/UpsilonTests/BasicMathExpressions.cs b/UpsilonTests/BasicMathExpressions.cs index a47e962..9b46b76 100644 --- a/UpsilonTests/BasicMathExpressions.cs +++ b/UpsilonTests/BasicMathExpressions.cs @@ -1,3 +1,5 @@ +using System; +using System.Diagnostics; using Upsilon.Evaluator; using Xunit; diff --git a/UpsilonTests/UserDataTests.cs b/UpsilonTests/UserDataTests.cs new file mode 100644 index 0000000..c390dd8 --- /dev/null +++ b/UpsilonTests/UserDataTests.cs @@ -0,0 +1,64 @@ +using System; +using Upsilon.BaseTypes.UserData; +using Upsilon.Evaluator; +using Xunit; + +namespace UpsilonTests +{ + public class UserDataTests : IClassFixture + { + public class UserDataTestsFixture : IDisposable + { + public UserDataTestsFixture() + { + UserDataTypeHandler.LoadType(); + } + + public void Dispose() + { + } + } + + #pragma warning disable 414, 649 + private class UserDataHelper + { + public string FieldString = "TestField"; + public string FieldStringSet; + } + #pragma warning restore 414, 649 + + + [Fact] + public void AccessFieldsGet() + { + var obj = new UserDataHelper(); + const string input = @" +function test(o) + return o[""FieldString""] +end +"; + var script = new Script(input); + Assert.Empty(script.Diagnostics.Messages); + var result = script.EvaluateFunction("test", new[] {obj}); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal("TestField", result); + } + + [Fact] + public void AccessFieldsSet() + { + var obj = new UserDataHelper(); + const string input = @" +function test(o) + o[""FieldStringSet""] = ""Test"" +end +"; + var script = new Script(input); + Assert.Empty(script.Diagnostics.Messages); + script.EvaluateFunction("test", new[] {obj}); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal("Test", obj.FieldStringSet); + } + + } +} \ No newline at end of file diff --git a/Ycicle/Program.cs b/Ycicle/Program.cs index ba447d4..46c05d8 100644 --- a/Ycicle/Program.cs +++ b/Ycicle/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; using Upsilon; using Upsilon.Evaluator; @@ -17,7 +18,6 @@ namespace Ycicle Console.Write("» "); var input = Console.ReadLine(); if (input == "exit") return; - script = script == null ? new Script(input) : Script.ContinueWith(script, input); if (script.Diagnostics.Messages.Count > 0) @@ -32,8 +32,8 @@ namespace Ycicle continue; } //Console.WriteLine(script.PrettyPrintSyntaxTree()); + var evaluate = script.Evaluate(); - var evaluate = script.Evaluate(); if (script.Diagnostics.Messages.Count > 0) { Console.ForegroundColor = ConsoleColor.Red;