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:
Deukhoofd 2018-11-24 13:35:40 +01:00
parent 806b3d5689
commit c63df3c941
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
13 changed files with 88 additions and 42 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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