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.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Upsilon.BaseTypes.LuaTypeInterfaces;
|
||||||
using Upsilon.BaseTypes.UserData;
|
using Upsilon.BaseTypes.UserData;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
|
@ -65,7 +66,15 @@ namespace Upsilon.BaseTypes
|
||||||
{
|
{
|
||||||
var types = variables.Select(x => x.GetCSharpType());
|
var types = variables.Select(x => x.GetCSharpType());
|
||||||
var method = _method.GetMethod(types.ToArray());
|
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();
|
return method.Invoke(_object, objects.ToArray()).ToLuaType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Upsilon.BaseTypes.LuaTypeInterfaces;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
|
||||||
namespace Upsilon.BaseTypes
|
namespace Upsilon.BaseTypes
|
||||||
{
|
{
|
||||||
internal class LuaTable : LuaType, IIndexable, IScopeOwner
|
internal class LuaTable : LuaType, IIndexable, IScopeOwner, IIterable
|
||||||
{
|
{
|
||||||
public EvaluationScope EvaluationScope { get; }
|
public EvaluationScope EvaluationScope { get; }
|
||||||
|
|
||||||
|
@ -15,7 +16,6 @@ namespace Upsilon.BaseTypes
|
||||||
EvaluationScope = scope;
|
EvaluationScope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override Type Type => Type.Table;
|
public override Type Type => Type.Table;
|
||||||
public override object ToCSharpObject()
|
public override object ToCSharpObject()
|
||||||
{
|
{
|
||||||
|
@ -43,5 +43,28 @@ namespace Upsilon.BaseTypes
|
||||||
var s = index.ToString();
|
var s = index.ToString();
|
||||||
EvaluationScope.Set(new VariableSymbol(s, value.Type, false), value);
|
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);
|
LuaType Get(Diagnostics diagnostics, TextSpan span, LuaType index, EvaluationScope scope);
|
||||||
void Set(Diagnostics diagnostics, TextSpan span, LuaType index, LuaType value);
|
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)
|
else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v)
|
||||||
{
|
{
|
||||||
v.Variable.Type = variable.Type;
|
v.Variable.Type = v.Type;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BaseTypes.LuaTypeInterfaces;
|
||||||
using Upsilon.BaseTypes.Number;
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.BaseTypes.UserData;
|
using Upsilon.BaseTypes.UserData;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
|
@ -11,10 +12,10 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
internal class Evaluator
|
internal class Evaluator
|
||||||
{
|
{
|
||||||
private readonly Diagnostics _diagnostics;
|
private Diagnostics _diagnostics;
|
||||||
private LuaType _lastValue;
|
private LuaType _lastValue;
|
||||||
private LuaType _returnValue;
|
private LuaType _returnValue;
|
||||||
internal EvaluationScope Scope { get; }
|
internal EvaluationScope Scope { get; private set; }
|
||||||
private bool HasReturned { get; set; }
|
private bool HasReturned { get; set; }
|
||||||
|
|
||||||
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
|
internal Evaluator(Diagnostics diagnostics, Dictionary<string, LuaType> variables)
|
||||||
|
@ -29,6 +30,13 @@ namespace Upsilon.Evaluator
|
||||||
Scope = new EvaluationScope(parentScope);
|
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)
|
public LuaType Evaluate(BoundScript e)
|
||||||
{
|
{
|
||||||
EvaluateNode(e.Statement);
|
EvaluateNode(e.Statement);
|
||||||
|
@ -282,9 +290,8 @@ namespace Upsilon.Evaluator
|
||||||
private void EvaluateMultiAssignmentStatement(BoundMultiAssignmentStatement e)
|
private void EvaluateMultiAssignmentStatement(BoundMultiAssignmentStatement e)
|
||||||
{
|
{
|
||||||
var val = EvaluateExpression(e.Assignment);
|
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++)
|
for (var i = 0; i < e.Variables.Length; i++)
|
||||||
{
|
{
|
||||||
var variableSymbol = e.Variables[i];
|
var variableSymbol = e.Variables[i];
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Parser;
|
using Upsilon.Parser;
|
||||||
|
using Upsilon.StandardLibraries;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Upsilon.Utilities;
|
using Upsilon.Utilities;
|
||||||
|
|
||||||
|
@ -19,13 +20,35 @@ namespace Upsilon.Evaluator
|
||||||
private Binder.Binder Binder { get; set; }
|
private Binder.Binder Binder { get; set; }
|
||||||
private EvaluationScope Scope { get; }
|
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)
|
public Script(string scriptString)
|
||||||
{
|
{
|
||||||
ScriptString = new SourceText(scriptString);
|
ScriptString = new SourceText(scriptString);
|
||||||
Diagnostics = new Diagnostics(ScriptString);
|
Diagnostics = new Diagnostics(ScriptString);
|
||||||
_parsed = Parser.Parser.Parse(scriptString, Diagnostics);
|
_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;
|
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