2018-11-30 11:07:18 +00:00
|
|
|
using System;
|
2018-12-06 15:06:42 +00:00
|
|
|
using System.Collections;
|
2018-11-28 20:23:08 +00:00
|
|
|
using System.Collections.Generic;
|
2018-12-05 16:20:28 +00:00
|
|
|
using System.Collections.Immutable;
|
2018-11-23 12:28:11 +00:00
|
|
|
using System.Linq;
|
|
|
|
using Upsilon.BaseTypes;
|
2018-11-30 14:28:36 +00:00
|
|
|
using Upsilon.BaseTypes.Number;
|
2018-12-09 12:23:09 +00:00
|
|
|
using Upsilon.BaseTypes.ScriptTable;
|
2018-11-30 14:28:36 +00:00
|
|
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
2018-12-07 15:11:52 +00:00
|
|
|
using Upsilon.BaseTypes.UserData;
|
2018-11-23 12:28:11 +00:00
|
|
|
using Upsilon.Binder;
|
2018-11-30 14:28:36 +00:00
|
|
|
using Upsilon.Binder.VariableSymbols;
|
2018-12-03 17:32:27 +00:00
|
|
|
using Upsilon.BoundTypes;
|
2018-11-23 12:28:11 +00:00
|
|
|
using Upsilon.Evaluator;
|
2018-11-30 14:28:36 +00:00
|
|
|
using Type = Upsilon.BaseTypes.Type;
|
2018-11-23 12:28:11 +00:00
|
|
|
|
|
|
|
namespace Upsilon.StandardLibraries
|
|
|
|
{
|
|
|
|
public static class StaticScope
|
|
|
|
{
|
|
|
|
private static EvaluationScope _staticScope;
|
|
|
|
private static BoundScope _staticBoundScope;
|
|
|
|
|
|
|
|
public static EvaluationScope Scope
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_staticScope != null)
|
|
|
|
return _staticScope;
|
2019-01-22 15:53:22 +00:00
|
|
|
lock (Scope)
|
|
|
|
{
|
|
|
|
var (evaluationScope, boundScope) = CreateStandardLibrary();
|
|
|
|
_staticScope = evaluationScope;
|
|
|
|
_staticBoundScope = boundScope;
|
|
|
|
return _staticScope;
|
|
|
|
}
|
2018-11-23 12:28:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static BoundScope BoundScope
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_staticBoundScope != null)
|
|
|
|
return _staticBoundScope;
|
|
|
|
|
|
|
|
var (evaluationScope, boundScope) = CreateStandardLibrary();
|
|
|
|
_staticScope = evaluationScope;
|
|
|
|
_staticBoundScope = boundScope;
|
|
|
|
return _staticBoundScope;
|
|
|
|
}
|
2018-12-12 19:43:12 +00:00
|
|
|
set => _staticBoundScope = value;
|
2018-11-23 12:28:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static (EvaluationScope, BoundScope) CreateStandardLibrary()
|
|
|
|
{
|
|
|
|
var basicFunctions = new BasicFunctions().LoadMethods();
|
2018-11-28 20:23:08 +00:00
|
|
|
var funcs = new Dictionary<string, ScriptType>();
|
|
|
|
var boundFuncs = new Dictionary<string, VariableSymbol>();
|
|
|
|
foreach (var func in basicFunctions)
|
|
|
|
{
|
2018-11-30 11:07:18 +00:00
|
|
|
funcs.Add(func.Key, func.Value.MethodInfoFunction);
|
2018-11-30 14:28:36 +00:00
|
|
|
var functionSymbol = new InternalFunctionVariableSymbol(func.Key, true,
|
|
|
|
func.Value.MethodInfoFunction.ReturnType.GetScriptType(),
|
2018-11-30 15:19:25 +00:00
|
|
|
func.Value.MethodInfoFunction.GetParameterInfo().Select(typeInfo =>
|
|
|
|
{
|
|
|
|
var derivedType = DeriveValidTypes(typeInfo.Type);
|
2018-12-13 18:04:23 +00:00
|
|
|
return new InternalFunctionVariableSymbol.InternalFunctionParameter(func.Key, derivedType,
|
2018-11-30 15:19:25 +00:00
|
|
|
typeInfo.IsOptional);
|
2019-01-18 15:09:25 +00:00
|
|
|
}).ToArray(), func.Value.MethodInfoFunction.Method.GetMethods()[0].Attribute.OverrideReturnType)
|
2018-11-30 11:07:18 +00:00
|
|
|
{
|
|
|
|
CommentValue = func.Value.CommentValue?.Split('\n')
|
|
|
|
};
|
|
|
|
boundFuncs.Add(func.Key, functionSymbol);
|
2018-11-28 20:23:08 +00:00
|
|
|
}
|
2018-12-07 15:11:52 +00:00
|
|
|
|
|
|
|
UserDataTypeHandler.LoadType<MathLibrary>();
|
|
|
|
funcs.Add("math", new MathLibrary().ToScriptType());
|
|
|
|
boundFuncs.Add("math",
|
2019-01-19 16:13:53 +00:00
|
|
|
new UserDataVariableSymbol("math", BoundTypeHandler.GetTypeDefinition(typeof(MathLibrary)), true));
|
2018-12-07 15:11:52 +00:00
|
|
|
|
2019-01-20 21:28:02 +00:00
|
|
|
UserDataTypeHandler.LoadType<ListLibrary>();
|
|
|
|
funcs.Add("list", new ListLibrary().ToScriptType());
|
|
|
|
boundFuncs.Add("list",
|
|
|
|
new UserDataVariableSymbol("list", BoundTypeHandler.GetTypeDefinition(typeof(ListLibrary)), true));
|
|
|
|
|
2018-11-28 20:23:08 +00:00
|
|
|
var scope = new EvaluationScope(funcs);
|
|
|
|
var boundScope = new BoundScope(boundFuncs, null);
|
2018-11-23 12:28:11 +00:00
|
|
|
return (scope, boundScope);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void RegisterStaticVariable(string name, object value)
|
|
|
|
{
|
2018-11-24 12:35:40 +00:00
|
|
|
var luaVariable = value.ToScriptType();
|
2018-12-03 17:32:27 +00:00
|
|
|
var ubDef = BoundTypeHandler.GetTypeDefinition(value.GetType());
|
2018-12-05 16:20:28 +00:00
|
|
|
VariableSymbol varSymbol = null;
|
|
|
|
if (ubDef != null)
|
|
|
|
{
|
2019-01-19 16:13:53 +00:00
|
|
|
varSymbol = new UserDataVariableSymbol(name, ubDef, true);
|
2018-12-05 16:20:28 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var type = value.GetType();
|
|
|
|
if (type.IsGenericType)
|
|
|
|
{
|
|
|
|
var generic = type.GetGenericTypeDefinition();
|
2018-12-06 14:45:19 +00:00
|
|
|
if (generic.FullName != null && generic.FullName.StartsWith("System.Func"))
|
2018-12-05 16:20:28 +00:00
|
|
|
{
|
|
|
|
varSymbol = BuildFunctionVariableSymbol(name, type);
|
|
|
|
}
|
2018-12-06 14:45:19 +00:00
|
|
|
else if (generic.FullName != null && generic.FullName.StartsWith("System.Action"))
|
|
|
|
{
|
|
|
|
varSymbol = BuildActionVariableSymbol(name, type);
|
|
|
|
}
|
2018-12-05 16:20:28 +00:00
|
|
|
}
|
|
|
|
if (varSymbol == null)
|
|
|
|
throw new Exception("Unknown type: " + type);
|
|
|
|
|
|
|
|
}
|
2018-11-24 11:42:54 +00:00
|
|
|
BoundScope.AssignToNearest(varSymbol);
|
|
|
|
Scope.AssignToNearest(varSymbol, luaVariable);
|
2018-11-23 12:28:11 +00:00
|
|
|
}
|
2018-11-30 14:28:36 +00:00
|
|
|
|
2018-12-05 16:20:28 +00:00
|
|
|
private static VariableSymbol BuildFunctionVariableSymbol(string name, System.Type type)
|
|
|
|
{
|
|
|
|
var genericParameters = type.GetGenericArguments();
|
2018-12-06 14:45:19 +00:00
|
|
|
var parameters = new List<InternalFunctionVariableSymbol.InternalFunctionParameter>();
|
2018-12-06 15:25:06 +00:00
|
|
|
if (genericParameters.Length > 1)
|
2018-12-05 16:20:28 +00:00
|
|
|
{
|
2018-12-06 15:25:06 +00:00
|
|
|
for (var i = 0; i < genericParameters.Length - 1; i++)
|
|
|
|
{
|
|
|
|
var t = DeriveValidTypes(genericParameters[i]);
|
2018-12-13 18:04:23 +00:00
|
|
|
parameters.Add(new InternalFunctionVariableSymbol.InternalFunctionParameter(name, t, false));
|
2018-12-06 15:25:06 +00:00
|
|
|
}
|
2018-12-05 16:20:28 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:25:06 +00:00
|
|
|
var result = genericParameters[genericParameters.Length - 1].GetScriptType();
|
2019-01-18 15:09:25 +00:00
|
|
|
return new InternalFunctionVariableSymbol(name, true, result, parameters.ToArray(), null);
|
2018-12-05 16:20:28 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 14:45:19 +00:00
|
|
|
private static VariableSymbol BuildActionVariableSymbol(string name, System.Type type)
|
|
|
|
{
|
|
|
|
var genericParameters = type.GetGenericArguments();
|
2018-12-06 15:06:42 +00:00
|
|
|
return new InternalFunctionVariableSymbol(name, true, Type.Nil,
|
|
|
|
genericParameters.Select(DeriveValidTypes).Select(t =>
|
2019-01-18 15:09:25 +00:00
|
|
|
new InternalFunctionVariableSymbol.InternalFunctionParameter(name, t, false)).ToArray(), null);
|
2018-12-06 14:45:19 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 15:09:25 +00:00
|
|
|
public static TypeContainer DeriveValidTypes(System.Type type)
|
2018-11-30 14:28:36 +00:00
|
|
|
{
|
2019-01-16 09:50:22 +00:00
|
|
|
if (type.IsEnum)
|
2019-01-22 12:39:57 +00:00
|
|
|
{
|
|
|
|
var boundEnumType = BoundTypeHandler.GetTypeName(type);
|
|
|
|
if (boundEnumType != null)
|
|
|
|
return new TypeContainer(Type.UserData | Type.Number, boundEnumType);
|
|
|
|
return new UndefinedUserDataTypeContainer(Type.UserData | Type.Number, type);
|
|
|
|
}
|
2019-01-16 09:50:22 +00:00
|
|
|
|
2018-12-09 13:14:43 +00:00
|
|
|
var typeCode = System.Type.GetTypeCode(type);
|
|
|
|
switch (typeCode)
|
|
|
|
{
|
|
|
|
case TypeCode.Boolean:
|
|
|
|
return Type.Boolean;
|
|
|
|
case TypeCode.Byte:
|
|
|
|
case TypeCode.SByte:
|
|
|
|
case TypeCode.Decimal:
|
|
|
|
case TypeCode.Double:
|
|
|
|
case TypeCode.Single:
|
|
|
|
case TypeCode.Int16:
|
|
|
|
case TypeCode.Int32:
|
|
|
|
case TypeCode.Int64:
|
|
|
|
case TypeCode.UInt16:
|
|
|
|
case TypeCode.UInt32:
|
|
|
|
case TypeCode.UInt64:
|
|
|
|
return Type.Number;
|
|
|
|
case TypeCode.Char:
|
|
|
|
case TypeCode.String:
|
|
|
|
return Type.String;
|
|
|
|
}
|
2018-11-30 14:28:36 +00:00
|
|
|
if (type == typeof(ScriptString))
|
|
|
|
return Type.String;
|
|
|
|
if (typeof(ScriptNumber).IsAssignableFrom(type))
|
|
|
|
return Type.Number;
|
|
|
|
if (type == typeof(ScriptBoolean))
|
|
|
|
return Type.Boolean;
|
|
|
|
if (typeof(ScriptTable).IsAssignableFrom(type))
|
|
|
|
return Type.Table;
|
2018-12-09 13:14:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (type == typeof(IIterable))
|
|
|
|
return Type.Table | Type.UserData;
|
|
|
|
|
2018-12-06 15:06:42 +00:00
|
|
|
if (typeof(IEnumerable).IsAssignableFrom(type))
|
|
|
|
return Type.Table | Type.UserData;
|
2019-01-17 18:24:00 +00:00
|
|
|
|
|
|
|
if (type == typeof(ScriptType))
|
|
|
|
// allows every type
|
|
|
|
return (Type) 255;
|
2019-01-22 12:39:57 +00:00
|
|
|
var boundType = BoundTypeHandler.GetTypeName(type);
|
|
|
|
if (boundType != null)
|
|
|
|
return new TypeContainer(boundType);
|
|
|
|
return Type.Unknown;
|
2018-11-30 14:28:36 +00:00
|
|
|
}
|
2018-11-23 12:28:11 +00:00
|
|
|
}
|
|
|
|
}
|