Some initial work on standard libraries

This commit is contained in:
Deukhoofd 2018-11-21 20:59:27 +01:00
parent 68830a1676
commit 1e9b0e0166
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
14 changed files with 263 additions and 15 deletions

View File

@ -1,6 +1,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Upsilon.BaseTypes.LuaTypeInterfaces;
using Upsilon.BaseTypes.UserData;
using Upsilon.Binder;
using Upsilon.Evaluator;
@ -65,7 +66,15 @@ namespace Upsilon.BaseTypes
{
var types = variables.Select(x => x.GetCSharpType());
var method = _method.GetMethod(types.ToArray());
var objects = variables.Select(x => x.ToCSharpObject());
var objects = variables.Select(x => x.ToCSharpObject()).ToList();
var pars = method.GetParameters();
if (pars.Length != objects.Count)
{
for (var i = objects.Count; i < pars.Length; i++)
{
objects.Add(null);
}
}
return method.Invoke(_object, objects.ToArray()).ToLuaType();
}
}

View File

@ -1,12 +1,13 @@
using System.Collections.Generic;
using System.Linq;
using Upsilon.BaseTypes.LuaTypeInterfaces;
using Upsilon.Binder;
using Upsilon.Evaluator;
using Upsilon.Text;
namespace Upsilon.BaseTypes
{
internal class LuaTable : LuaType, IIndexable, IScopeOwner
internal class LuaTable : LuaType, IIndexable, IScopeOwner, IIterable
{
public EvaluationScope EvaluationScope { get; }
@ -15,7 +16,6 @@ namespace Upsilon.BaseTypes
EvaluationScope = scope;
}
public override Type Type => Type.Table;
public override object ToCSharpObject()
{
@ -43,5 +43,28 @@ namespace Upsilon.BaseTypes
var s = index.ToString();
EvaluationScope.Set(new VariableSymbol(s, value.Type, false), value);
}
private IEnumerator<KeyValuePair<string, LuaType>> _enumerator;
public bool Next(out LuaType key, out LuaType next)
{
if (_enumerator == null) _enumerator = EvaluationScope.Variables.GetEnumerator();
if (_enumerator.MoveNext())
{
key = _enumerator.Current.Key.ToLuaType();
next = _enumerator.Current.Value;
return true;
}
key = null;
next = null;
Reset();
return false;
}
public void Reset()
{
_enumerator = null;
}
}
}

View File

@ -0,0 +1,8 @@
namespace Upsilon.BaseTypes.LuaTypeInterfaces
{
public interface IIterable
{
bool Next(out LuaType key, out LuaType next);
void Reset();
}
}

View File

@ -8,9 +8,4 @@ namespace Upsilon.BaseTypes
LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope);
void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value);
}
internal interface IScopeOwner
{
EvaluationScope EvaluationScope { get; }
}
}

View File

@ -0,0 +1,9 @@
using Upsilon.Evaluator;
namespace Upsilon.BaseTypes.LuaTypeInterfaces
{
internal interface IScopeOwner
{
EvaluationScope EvaluationScope { get; }
}
}

View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using Upsilon.Evaluator;
using Upsilon.Text;
namespace Upsilon.BaseTypes
{
internal class SimpleLuaTable : LuaType, IIndexable
{
private readonly IList<LuaType> _objects;
public SimpleLuaTable(IList<LuaType> objects)
{
_objects = objects;
}
public LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope)
{
int i;
switch (index.Type)
{
case Type.String:
{
var str = (LuaString)index;
i = int.Parse(str.Value) - 1;
break;
}
case Type.Number:
{
var ind = (Number.NumberLong) index;
i = (int) ind.Value - 1;
break;
}
default:
return null;
}
return _objects[i];
}
public void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value)
{
throw new System.NotImplementedException();
}
public override Type Type => Type.Table;
public override object ToCSharpObject()
{
return _objects;
}
public override System.Type GetCSharpType()
{
return _objects.GetType();
}
}
}

View File

@ -258,7 +258,7 @@ namespace Upsilon.Binder
}
else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v)
{
v.Variable.Type = variable.Type;
v.Variable.Type = v.Type;
}
else
{

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Upsilon.BaseTypes;
using Upsilon.BaseTypes.LuaTypeInterfaces;
using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.UserData;
using Upsilon.Binder;
@ -11,10 +12,10 @@ namespace Upsilon.Evaluator
{
internal class Evaluator
{
private readonly Diagnostics _diagnostics;
private Diagnostics _diagnostics;
private LuaType _lastValue;
private LuaType _returnValue;
internal EvaluationScope Scope { get; }
internal EvaluationScope Scope { get; private set; }
private bool HasReturned { get; set; }
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
@ -29,6 +30,13 @@ namespace Upsilon.Evaluator
Scope = new EvaluationScope(parentScope);
}
private Evaluator(){}
internal static Evaluator CreateWithSetScope(Diagnostics diagnostics, EvaluationScope scope)
{
return new Evaluator {_diagnostics = diagnostics, Scope = scope};
}
public LuaType Evaluate(BoundScript e)
{
EvaluateNode(e.Statement);
@ -282,9 +290,8 @@ namespace Upsilon.Evaluator
private void EvaluateMultiAssignmentStatement(BoundMultiAssignmentStatement e)
{
var val = EvaluateExpression(e.Assignment);
if (val.Type == Type.Table)
if (val is IIndexable table)
{
var table = (LuaTable) val;
for (var i = 0; i < e.Variables.Length; i++)
{
var variableSymbol = e.Variables[i];

View File

@ -4,6 +4,7 @@ using System.Collections.Immutable;
using Upsilon.BaseTypes;
using Upsilon.Binder;
using Upsilon.Parser;
using Upsilon.StandardLibraries;
using Upsilon.Text;
using Upsilon.Utilities;
@ -19,13 +20,35 @@ namespace Upsilon.Evaluator
private Binder.Binder Binder { get; set; }
private EvaluationScope Scope { get; }
private static BoundScope _staticBoundScope;
private static EvaluationScope _staticScope;
private static EvaluationScope StaticScope
{
get
{
var scope = _staticScope;
if (scope != null)
{
return scope;
}
var (evaluationScope, boundScope) = StandardLibrary.Create();
_staticBoundScope = boundScope;
return (_staticScope = evaluationScope);
}
}
public Script(string scriptString)
{
ScriptString = new SourceText(scriptString);
Diagnostics = new Diagnostics(ScriptString);
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
Binder = new Binder.Binder(Diagnostics, new Dictionary<string, VariableSymbol>());
Evaluator = new Evaluator( Diagnostics, new Dictionary<string, LuaType>());
Scope = EvaluationScope.CreateWithGetOnlyParent(StaticScope);
Binder = new Binder.Binder(Diagnostics, _staticBoundScope.Variables);
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope);
Scope = Evaluator.Scope;
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using Upsilon.BaseTypes;
using Upsilon.BaseTypes.LuaTypeInterfaces;
// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global
namespace Upsilon.StandardLibraries
{
internal class BasicFunctions : LuaLibrary
{
[LuaFunction("assert")]
public void Assert(bool boolean, string message = null)
{
if (!boolean)
{
Error(message ?? "assertion failed!");
}
}
[LuaFunction("error")]
public void Error(string message)
{
throw new Exception(message);
}
[LuaFunction("ipairs")]
public LuaType Pairs(IIterable table)
{
if (!table.Next(out var key, out var next))
{
return new LuaNull();
}
return new SimpleLuaTable(new List<LuaType>() {key, next});
}
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace Upsilon.StandardLibraries
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class LuaFunctionAttribute : Attribute
{
public LuaFunctionAttribute(string name)
{
Name = name;
}
public string Name { get; }
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Reflection;
using Upsilon.BaseTypes;
using Upsilon.BaseTypes.UserData;
namespace Upsilon.StandardLibraries
{
internal abstract class LuaLibrary
{
public Dictionary<string, LuaFunction> LoadMethods()
{
var dictionary = new Dictionary<string, LuaFunction>();
var methods = GetType().GetMethods();
foreach (var methodInfo in methods)
{
var attr = methodInfo.GetCustomAttribute<LuaFunctionAttribute>();
if (attr != null)
{
dictionary.Add(attr.Name, new LuaMethodInfoFunction(new UserDataMethod(methodInfo), this));
}
}
return dictionary;
}
}
}

View File

@ -0,0 +1,23 @@
using System.Collections.Immutable;
using System.Linq;
using Upsilon.BaseTypes;
using Upsilon.Binder;
using Upsilon.Evaluator;
namespace Upsilon.StandardLibraries
{
internal class StandardLibrary
{
public static (EvaluationScope, BoundScope) Create()
{
var basicFunctions = new BasicFunctions().LoadMethods();
var scope = new EvaluationScope(basicFunctions.ToDictionary(x => x.Key, x => (LuaType)x.Value));
var boundScope =
new BoundScope(
scope.Variables.ToDictionary(x => x.Key
, x => (VariableSymbol)new FunctionVariableSymbol(x.Key, x.Value.Type, false, ImmutableArray<VariableSymbol>.Empty){IsBound = true}),
null);
return (scope, boundScope);
}
}
}

View File

@ -0,0 +1,14 @@
using Upsilon.Evaluator;
using Xunit;
namespace UpsilonTests.StandardLibraryTests
{
public class BasicFunctionsTests
{
[Fact]
public void Assert()
{
new Script("assert(true)").Evaluate();
}
}
}