Work on standard libraries.
- Allows Standard Libraries to work with actual luatypes, to prevent constant back and forth casting - adds ipairs function, doesn't do anything except maintain compatibility with lua - several tests
This commit is contained in:
parent
806b3d5689
commit
c63df3c941
|
@ -1,3 +1,6 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
@ -53,20 +56,32 @@ namespace Upsilon.BaseTypes
|
|||
|
||||
internal class ScriptMethodInfoFunction : ScriptFunction
|
||||
{
|
||||
public ScriptMethodInfoFunction(UserDataMethod method, object o)
|
||||
public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation)
|
||||
{
|
||||
_method = method;
|
||||
_object = o;
|
||||
_directTypeManipulation = directTypeManipulation;
|
||||
}
|
||||
|
||||
private readonly UserDataMethod _method;
|
||||
private readonly object _object;
|
||||
private readonly bool _directTypeManipulation;
|
||||
|
||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables)
|
||||
{
|
||||
var types = variables.Select(x => x.GetCSharpType());
|
||||
var method = _method.GetMethod(types.ToArray());
|
||||
var objects = variables.Select(x => x.ToCSharpObject()).ToList();
|
||||
var types = _directTypeManipulation
|
||||
? variables.Select(x => x.GetType()).ToArray()
|
||||
: variables.Select(x => x.GetCSharpType()).ToArray();
|
||||
var method = _method.GetMethod(types);
|
||||
if (method == null)
|
||||
{
|
||||
throw new Exception(
|
||||
$"No valid function found on type '{_object.GetType()}' with name '{_method.Name}' " +
|
||||
$"and parameter types: {string.Join(", ", types.Select(x => $"'{x.Name}'"))}");
|
||||
}
|
||||
var objects = _directTypeManipulation
|
||||
? variables.Select(x => (object) x).ToList()
|
||||
: variables.Select(x => x.ToCSharpObject()).ToList();
|
||||
var pars = method.GetParameters();
|
||||
if (pars.Length != objects.Count)
|
||||
{
|
||||
|
@ -78,7 +93,10 @@ namespace Upsilon.BaseTypes
|
|||
|
||||
try
|
||||
{
|
||||
return method.Invoke(_object, objects.ToArray()).ToLuaType();
|
||||
var result = method.Invoke(_object, objects.ToArray());
|
||||
if (_directTypeManipulation)
|
||||
return (ScriptType)result;
|
||||
return result.ToScriptType();
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Upsilon.BaseTypes
|
|||
{
|
||||
internal static class TypeConversion
|
||||
{
|
||||
public static ScriptType ToLuaType(this object o)
|
||||
public static ScriptType ToScriptType(this object o)
|
||||
{
|
||||
if (o is ScriptType type) return type;
|
||||
switch (o)
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Upsilon.BaseTypes.UserData
|
|||
var key = index.ToCSharpObject();
|
||||
if (Dictionary.Contains(key))
|
||||
{
|
||||
return Dictionary[key].ToLuaType();
|
||||
return Dictionary[key].ToScriptType();
|
||||
}
|
||||
//TODO: log error
|
||||
return new ScriptNull();
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Upsilon.BaseTypes.UserData
|
|||
{
|
||||
return null;
|
||||
}
|
||||
return List[i].ToLuaType();
|
||||
return List[i].ToScriptType();
|
||||
}
|
||||
|
||||
public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value)
|
||||
|
|
|
@ -30,10 +30,12 @@ namespace Upsilon.BaseTypes.UserData
|
|||
public bool IsOptional { get; }
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
private List<UserDataMethodPart> MethodParts { get; }
|
||||
|
||||
public UserDataMethod(MethodInfo method)
|
||||
{
|
||||
Name = method.Name;
|
||||
var part = new UserDataMethodPart(method);
|
||||
MethodParts = new List<UserDataMethodPart>()
|
||||
{
|
||||
|
|
|
@ -40,15 +40,15 @@ namespace Upsilon.BaseTypes.UserData
|
|||
member = member.ToLowerInvariant();
|
||||
if (Variables.TryGetValue(member, out var info))
|
||||
{
|
||||
return (info.GetValue(value).ToLuaType(), false, null);
|
||||
return (info.GetValue(value).ToScriptType(), false, null);
|
||||
}
|
||||
if (Properties.TryGetValue(member, out var property))
|
||||
{
|
||||
return (property.GetValue(value).ToLuaType(), false, null);
|
||||
return (property.GetValue(value).ToScriptType(), false, null);
|
||||
}
|
||||
if (Methods.TryGetValue(member, out var method))
|
||||
{
|
||||
return (new ScriptMethodInfoFunction(method, value), false, null);
|
||||
return (new ScriptMethodInfoFunction(method, value, false), false, null);
|
||||
}
|
||||
|
||||
return (null, true, $"Can't find public member '{member}' on type '{Type}'.");
|
||||
|
@ -85,7 +85,7 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return (new ScriptNull(), true);
|
||||
}
|
||||
|
||||
return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToLuaType(), false);
|
||||
return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToScriptType(), false);
|
||||
}
|
||||
public (ScriptType Type, bool Failed) UnaryOperator(object value, ScriptType par1, OperatorType op)
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return (new ScriptNull(), true);
|
||||
}
|
||||
|
||||
return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToLuaType(), false);
|
||||
return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToScriptType(), false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -476,7 +476,7 @@ namespace Upsilon.Evaluator
|
|||
scope = scopeOwner.EvaluationScope;
|
||||
}
|
||||
|
||||
return indexable.Get(_diagnostics, e.Span, e.Index.ToLuaType(), scope);
|
||||
return indexable.Get(_diagnostics, e.Span, e.Index.ToScriptType(), scope);
|
||||
}
|
||||
|
||||
private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e)
|
||||
|
@ -491,7 +491,7 @@ namespace Upsilon.Evaluator
|
|||
else
|
||||
{
|
||||
table = EvaluateExpression(((BoundFullStopIndexExpression)e.TableIndexExpression).Expression);
|
||||
index = ((BoundFullStopIndexExpression) e.TableIndexExpression).Index.ToLuaType();
|
||||
index = ((BoundFullStopIndexExpression) e.TableIndexExpression).Index.ToScriptType();
|
||||
}
|
||||
|
||||
var value = EvaluateExpression(e.Value);
|
||||
|
@ -499,7 +499,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
throw new Exception("Cant assign to that");
|
||||
}
|
||||
indexable.Set(_diagnostics, e.Span, index.ToString().ToLuaType(), value);
|
||||
indexable.Set(_diagnostics, e.Span, index.ToString().ToScriptType(), value);
|
||||
}
|
||||
|
||||
private void EvaluateNumericForStatement(BoundNumericForStatement e)
|
||||
|
@ -550,7 +550,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
var (key, value) = enumerator.Current;
|
||||
if (e.Variables[0].Name != "_")
|
||||
innerEvaluator.Scope.CreateLocal(e.Variables[0], key.ToLuaType());
|
||||
innerEvaluator.Scope.CreateLocal(e.Variables[0], key.ToScriptType());
|
||||
if (e.Variables[1].Name != "_")
|
||||
innerEvaluator.Scope.CreateLocal(e.Variables[1], value);
|
||||
innerEvaluator.EvaluateBoundBlockStatement((BoundBlockStatement) e.Block);
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
luaParameters.Add(parameter.ToLuaType());
|
||||
luaParameters.Add(parameter.ToScriptType());
|
||||
}
|
||||
}
|
||||
return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
|
||||
|
@ -103,7 +103,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
luaParameters.Add(parameter.ToLuaType());
|
||||
luaParameters.Add(parameter.ToScriptType());
|
||||
}
|
||||
}
|
||||
return Convert<T>(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
|
||||
|
|
|
@ -12,36 +12,31 @@ namespace Upsilon.StandardLibraries
|
|||
{
|
||||
internal class BasicFunctions : LuaLibrary
|
||||
{
|
||||
[LuaFunction("assert")]
|
||||
public void Assert(bool boolean, string message = null)
|
||||
[StandardLibraryScriptFunction("assert")]
|
||||
public void Assert(ScriptBoolean boolean, ScriptString message = null)
|
||||
{
|
||||
if (!boolean)
|
||||
{
|
||||
Error(message ?? "assertion failed!");
|
||||
Error(message ?? new ScriptString("assertion failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
[LuaFunction("error")]
|
||||
public void Error(string message)
|
||||
[StandardLibraryScriptFunction("error")]
|
||||
public void Error(ScriptString message)
|
||||
{
|
||||
throw new Exception(message);
|
||||
throw new Exception(message.Value);
|
||||
}
|
||||
|
||||
/*
|
||||
[LuaFunction("ipairs")]
|
||||
public ScriptType Pairs(IIterable table)
|
||||
[StandardLibraryScriptFunction("ipairs")]
|
||||
public IIterable Pairs(IIterable table)
|
||||
{
|
||||
if (!table.Next(out var key, out var next))
|
||||
{
|
||||
return new ScriptNull();
|
||||
return table;
|
||||
}
|
||||
|
||||
return new SimpleScriptTable(new List<ScriptType>() {key, next});
|
||||
}*/
|
||||
|
||||
[LuaFunction("tonumber")]
|
||||
public ScriptNumber ToNumber(string str)
|
||||
[StandardLibraryScriptFunction("tonumber")]
|
||||
public ScriptNumber ToNumber(ScriptString obj)
|
||||
{
|
||||
var str = obj.Value;
|
||||
if (str.Contains("."))
|
||||
{
|
||||
return new ScriptNumberDouble(double.Parse(str));
|
||||
|
|
|
@ -13,10 +13,10 @@ namespace Upsilon.StandardLibraries
|
|||
var methods = GetType().GetMethods();
|
||||
foreach (var methodInfo in methods)
|
||||
{
|
||||
var attr = methodInfo.GetCustomAttribute<LuaFunctionAttribute>();
|
||||
var attr = methodInfo.GetCustomAttribute<StandardLibraryScriptFunctionAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
dictionary.Add(attr.Name, new ScriptMethodInfoFunction(new UserDataMethod(methodInfo), this));
|
||||
dictionary.Add(attr.Name, new ScriptMethodInfoFunction(new UserDataMethod(methodInfo), this, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ using System;
|
|||
namespace Upsilon.StandardLibraries
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class LuaFunctionAttribute : Attribute
|
||||
public class StandardLibraryScriptFunctionAttribute : Attribute
|
||||
{
|
||||
public LuaFunctionAttribute(string name)
|
||||
public StandardLibraryScriptFunctionAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
|
@ -54,7 +54,7 @@ namespace Upsilon.StandardLibraries
|
|||
|
||||
public static void RegisterStaticVariable(string name, object value)
|
||||
{
|
||||
var luaVariable = value.ToLuaType();
|
||||
var luaVariable = value.ToScriptType();
|
||||
var varSymbol = new VariableSymbol(name, luaVariable.Type, false);
|
||||
BoundScope.AssignToNearest(varSymbol);
|
||||
Scope.AssignToNearest(varSymbol, luaVariable);
|
||||
|
|
|
@ -25,5 +25,36 @@ namespace UpsilonTests.StandardLibraryTests
|
|||
Assert.Equal("test_error", e.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IPairsTest()
|
||||
{
|
||||
const string input = @"
|
||||
arr = {100, 56, 28}
|
||||
value = 0
|
||||
for key, val in ipairs(arr) do
|
||||
value = value + val
|
||||
end
|
||||
return value
|
||||
";
|
||||
var script = new Script(input, BoundScope, StaticScope);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var result = script.Evaluate<long>();
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(184, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToNumberTest()
|
||||
{
|
||||
const string input = @"
|
||||
return tonumber(""100"")
|
||||
";
|
||||
var script = new Script(input, BoundScope, StaticScope);
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
var result = script.Evaluate<long>();
|
||||
Assert.Empty(script.Diagnostics.Messages);
|
||||
Assert.Equal(100, result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue