Some initial work on standard libraries
This commit is contained in:
parent
68830a1676
commit
1e9b0e0166
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Upsilon.BaseTypes.LuaTypeInterfaces
|
||||
{
|
||||
public interface IIterable
|
||||
{
|
||||
bool Next(out LuaType key, out LuaType next);
|
||||
void Reset();
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Upsilon.Evaluator;
|
||||
|
||||
namespace Upsilon.BaseTypes.LuaTypeInterfaces
|
||||
{
|
||||
internal interface IScopeOwner
|
||||
{
|
||||
EvaluationScope EvaluationScope { get; }
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Upsilon.Evaluator;
|
||||
using Xunit;
|
||||
|
||||
namespace UpsilonTests.StandardLibraryTests
|
||||
{
|
||||
public class BasicFunctionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Assert()
|
||||
{
|
||||
new Script("assert(true)").Evaluate();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue