Various changes and tweaks to run better
This commit is contained in:
parent
f6947194b9
commit
43d9360145
|
@ -44,16 +44,6 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
|
||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope)
|
||||
{
|
||||
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 = new List<object>();
|
||||
if (_passScriptReference)
|
||||
objects.Add(script);
|
||||
|
@ -62,19 +52,11 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
|||
objects.AddRange(_directTypeManipulation
|
||||
? variables.Select(x => (object) x).ToList()
|
||||
: 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);
|
||||
}
|
||||
}
|
||||
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = method.Invoke(_object, objects.ToArray());
|
||||
result = _object.GetType().InvokeMember(_method.Name, BindingFlags.InvokeMethod, System.Type.DefaultBinder,
|
||||
_object, objects.ToArray());
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using Upsilon.BaseTypes.Number;
|
|||
using Upsilon.BaseTypes.ScriptFunction;
|
||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||
using Upsilon.BaseTypes.UserData;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes
|
||||
{
|
||||
|
@ -19,6 +20,8 @@ namespace Upsilon.BaseTypes
|
|||
return new ScriptBoolean(b);
|
||||
case int i:
|
||||
return new ScriptNumberLong(i);
|
||||
case short s:
|
||||
return new ScriptNumberLong(s);
|
||||
case long i:
|
||||
return new ScriptNumberLong(i);
|
||||
case float f:
|
||||
|
|
|
@ -5,10 +5,10 @@ namespace Upsilon.BaseTypes.UserData
|
|||
{
|
||||
internal sealed class GenericUserData : ScriptType, IUserData
|
||||
{
|
||||
public GenericUserData(object dictionary)
|
||||
public GenericUserData(object obj)
|
||||
{
|
||||
Value = dictionary;
|
||||
_typeInfo = UserDataTypeHandler.GetTypeInfo(dictionary.GetType());
|
||||
Value = obj;
|
||||
_typeInfo = UserDataTypeHandler.GetTypeInfo(obj.GetType());
|
||||
}
|
||||
public override Type Type => Type.UserData;
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]
|
||||
public class UpsilonHiddenAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@ using System;
|
|||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, AllowMultiple = false, Inherited = true)]
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface,
|
||||
AllowMultiple = false, Inherited = true)]
|
||||
public class UpsilonUserDataAttribute : Attribute
|
||||
{
|
||||
public UpsilonUserDataAttribute(string name)
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace Upsilon.BaseTypes.UserData
|
|||
public UserDataMethodParameter(ParameterInfo info)
|
||||
{
|
||||
Type = info.ParameterType;
|
||||
if (Type.IsGenericType)
|
||||
Type = Type.GetGenericTypeDefinition();
|
||||
IsOptional = info.IsOptional;
|
||||
}
|
||||
|
||||
|
@ -89,6 +91,7 @@ namespace Upsilon.BaseTypes.UserData
|
|||
break;
|
||||
}
|
||||
var parameter = parameterTypes[index];
|
||||
if (parameter.IsGenericType) parameter = parameter.GetGenericTypeDefinition();
|
||||
if (userDataMethodParameter.Type != parameter &&
|
||||
!userDataMethodParameter.Type.IsAssignableFrom(parameter))
|
||||
{
|
||||
|
|
|
@ -10,12 +10,20 @@ namespace Upsilon.BaseTypes.UserData
|
|||
{
|
||||
public UserDataType(System.Type type)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
type = type.GetGenericTypeDefinition();
|
||||
}
|
||||
Type = type;
|
||||
Variables = type.GetFields().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
|
||||
Properties = type.GetProperties().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
|
||||
Methods = new Dictionary<string, UserDataMethod>();
|
||||
foreach (var methodInfo in type.GetMethods())
|
||||
{
|
||||
var hiddenAttribute = methodInfo.GetCustomAttribute(typeof(UpsilonHiddenAttribute));
|
||||
if (hiddenAttribute != null)
|
||||
continue;
|
||||
|
||||
var commonName = methodInfo.Name.ToLowerInvariant();
|
||||
var attribute = methodInfo.GetCustomAttribute(typeof(ScriptFunctionAttribute));
|
||||
if (attribute is ScriptFunctionAttribute sfa )
|
||||
|
@ -43,7 +51,10 @@ namespace Upsilon.BaseTypes.UserData
|
|||
|
||||
public (ScriptType Type, bool Failed, string Error) Get(object value, string member)
|
||||
{
|
||||
if (value.GetType() != Type)
|
||||
var valueType = value.GetType();
|
||||
if (valueType.IsGenericType)
|
||||
valueType = valueType.GetGenericTypeDefinition();
|
||||
if (valueType != Type)
|
||||
return (null, true, "Invalid Type");
|
||||
member = member.ToLowerInvariant();
|
||||
if (Variables.TryGetValue(member, out var info))
|
||||
|
@ -93,6 +104,12 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return (new ScriptNull(), true);
|
||||
}
|
||||
|
||||
// HACK: Ugly solution for generic methods
|
||||
if (method.ContainsGenericParameters)
|
||||
{
|
||||
method = value.GetType().GetMethod(method.Name, new[] {par1.GetCSharpType(), par2.GetCSharpType()});
|
||||
}
|
||||
|
||||
return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToScriptType(), false);
|
||||
}
|
||||
public (ScriptType Type, bool Failed) UnaryOperator(object value, ScriptType par1, OperatorType op)
|
||||
|
@ -103,6 +120,12 @@ namespace Upsilon.BaseTypes.UserData
|
|||
return (new ScriptNull(), true);
|
||||
}
|
||||
|
||||
// HACK: Ugly solution for generic methods
|
||||
if (method.ContainsGenericParameters)
|
||||
{
|
||||
method = value.GetType().GetMethod(method.Name, new[] {par1.GetCSharpType()});
|
||||
}
|
||||
|
||||
return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToScriptType(), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Upsilon.BoundTypes;
|
||||
using Upsilon.Exceptions;
|
||||
using Upsilon.StandardLibraries;
|
||||
using Upsilon.Text;
|
||||
|
||||
namespace Upsilon.BaseTypes.UserData
|
||||
{
|
||||
public static class UserDataTypeHandler
|
||||
{
|
||||
private static readonly Dictionary<System.Type, UserDataType> Types = new Dictionary<System.Type, UserDataType>();
|
||||
private static readonly ConcurrentDictionary<System.Type, UserDataType> Types
|
||||
= new ConcurrentDictionary<System.Type, UserDataType>();
|
||||
|
||||
public static void LoadType(System.Type t, string name)
|
||||
{
|
||||
var info = new UserDataType(t);
|
||||
Types.Add(t, info);
|
||||
Types.AddOrUpdate(t, info, (type, dataType) => dataType);
|
||||
UserDataBoundTypeDefinition boundType;
|
||||
if (t.IsEnum)
|
||||
{
|
||||
|
@ -55,7 +59,14 @@ namespace Upsilon.BaseTypes.UserData
|
|||
|
||||
internal static UserDataType GetTypeInfo(System.Type t)
|
||||
{
|
||||
return Types[t];
|
||||
if (t.IsGenericType)
|
||||
t = t.GetGenericTypeDefinition();
|
||||
if (Types.TryGetValue(t, out var result))
|
||||
return result;
|
||||
else
|
||||
{
|
||||
throw new Exception($"Can't use type '{t.FullName}' as script type, it's not registered for use.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -86,6 +86,9 @@ namespace Upsilon.BaseTypes.UserData
|
|||
{
|
||||
return null;
|
||||
}
|
||||
if (t1.IsGenericType) t1 = t1.GetGenericTypeDefinition();
|
||||
if (t2.IsGenericType) t2 = t2.GetGenericTypeDefinition();
|
||||
|
||||
|
||||
foreach (var operatorMethod in m)
|
||||
{
|
||||
|
|
|
@ -316,10 +316,12 @@ namespace Upsilon.Binder
|
|||
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) indexerVariable).BoundTypeDefinition;
|
||||
var bDefProperty = parent.Properties[fullStopIndexExpression.Index.ToLowerInvariant()];
|
||||
var boundDef = BoundTypeHandler.GetTypeDefinition(bDefProperty.ActualType);
|
||||
if (boundDef != null)
|
||||
{
|
||||
return new UserDataVariableSymbol(fullStopIndexExpression.Index, boundDef, parent);
|
||||
}
|
||||
|
||||
if (indexerVariable.Type == Type.Unknown)
|
||||
}
|
||||
else if (indexerVariable.Type == Type.Unknown)
|
||||
{
|
||||
if (indexerVariable is UserDataVariableSymbol funcSymbol)
|
||||
{
|
||||
|
@ -335,8 +337,7 @@ namespace Upsilon.Binder
|
|||
return new VariableSymbol(fullStopIndexExpression.Index, Type.Unknown, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (expression.Kind == BoundKind.BoundFunctionCallExpression)
|
||||
else if (expression.Kind == BoundKind.BoundFunctionCallExpression)
|
||||
{
|
||||
return new VariableSymbol("", expression.Type, true);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using Upsilon.BaseTypes;
|
||||
|
||||
|
@ -7,33 +7,29 @@ namespace Upsilon.BoundTypes
|
|||
{
|
||||
public static class BoundTypeHandler
|
||||
{
|
||||
private static readonly Dictionary<string, BoundTypeDefinition> DefaultTypeDefinitions =
|
||||
new Dictionary<string, BoundTypeDefinition>
|
||||
private static void AddDefaults(ConcurrentDictionary<string, BoundTypeDefinition> dic)
|
||||
{
|
||||
{"string", new BoundTypeDefinition(Type.String, typeof(string))},
|
||||
{
|
||||
"number",
|
||||
new BoundTypeDefinition(Type.Number,
|
||||
new[] {typeof(int), typeof(long), typeof(float), typeof(double)})
|
||||
},
|
||||
{"bool", new BoundTypeDefinition(Type.Boolean, typeof(bool))},
|
||||
{"table", new BoundTypeDefinition(Type.Table, typeof(IEnumerator))},
|
||||
{"function", new BoundTypeDefinition(Type.Function, new System.Type[0])},
|
||||
};
|
||||
dic.TryAdd("string", new BoundTypeDefinition(Type.String, typeof(string)));
|
||||
dic.TryAdd("number", new BoundTypeDefinition(Type.Number,
|
||||
new[] {typeof(int), typeof(long), typeof(float), typeof(double)}));
|
||||
dic.TryAdd("bool", new BoundTypeDefinition(Type.Boolean, typeof(bool)));
|
||||
dic.TryAdd("table", new BoundTypeDefinition(Type.Table, typeof(IEnumerator)));
|
||||
dic.TryAdd("function", new BoundTypeDefinition(Type.Function, new System.Type[0]));
|
||||
}
|
||||
|
||||
private static Dictionary<string, BoundTypeDefinition> _typeDefinitions =
|
||||
new Dictionary<string, BoundTypeDefinition>(DefaultTypeDefinitions);
|
||||
private static readonly ConcurrentDictionary<string, BoundTypeDefinition> TypeDefinitions = Reset();
|
||||
|
||||
public static void Reset()
|
||||
public static ConcurrentDictionary<string, BoundTypeDefinition> Reset()
|
||||
{
|
||||
_typeDefinitions =
|
||||
new Dictionary<string, BoundTypeDefinition>(DefaultTypeDefinitions);
|
||||
var dic = new ConcurrentDictionary<string, BoundTypeDefinition>();
|
||||
AddDefaults(dic);
|
||||
return dic;
|
||||
}
|
||||
|
||||
public static BoundTypeDefinition GetTypeDefinition(string key)
|
||||
{
|
||||
var normalizedName = key.ToLowerInvariant();
|
||||
if (_typeDefinitions.TryGetValue(normalizedName, out var bt))
|
||||
if (TypeDefinitions.TryGetValue(normalizedName, out var bt))
|
||||
{
|
||||
return bt;
|
||||
}
|
||||
|
@ -42,20 +38,13 @@ namespace Upsilon.BoundTypes
|
|||
|
||||
public static BoundTypeDefinition GetTypeDefinition(System.Type type)
|
||||
{
|
||||
return _typeDefinitions.Values.FirstOrDefault(x => x.ValidInternalTypes.Contains(type));
|
||||
return TypeDefinitions.Values.FirstOrDefault(x => x.ValidInternalTypes.Contains(type));
|
||||
}
|
||||
|
||||
public static void LoadUserDataTypeDefinition(UserDataBoundTypeDefinition def)
|
||||
{
|
||||
var key = def.Name.ToLowerInvariant();
|
||||
if (_typeDefinitions.ContainsKey(key))
|
||||
{
|
||||
_typeDefinitions[key] = def;
|
||||
}
|
||||
else
|
||||
{
|
||||
_typeDefinitions.Add(key, def);
|
||||
}
|
||||
TypeDefinitions.AddOrUpdate(key, def, (s, definition) => definition);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,9 +75,26 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
for (var index = 0; index < parameters.Length; index++)
|
||||
{
|
||||
var parameter = parameters[index];
|
||||
var parameterSymbol = (UserDataVariableSymbol)function.Parameters[index].VariableSymbol;
|
||||
if (parameterSymbol.BoundTypeDefinition != null)
|
||||
object parameter;
|
||||
if (index < parameters.Length)
|
||||
{
|
||||
parameter = parameters[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
parameter = null;
|
||||
}
|
||||
|
||||
UserDataVariableSymbol parameterSymbol;
|
||||
if (index < function.Parameters.Length)
|
||||
{
|
||||
parameterSymbol = (UserDataVariableSymbol)function.Parameters[index].VariableSymbol;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (parameterSymbol.BoundTypeDefinition != null && parameter != null)
|
||||
{
|
||||
bool isCompatible = false;
|
||||
var parameterType = parameter.GetType();
|
||||
|
@ -97,7 +114,8 @@ namespace Upsilon.Evaluator
|
|||
}
|
||||
}
|
||||
|
||||
innerEvaluator.Scope.CreateLocal(parameterSymbol, parameter.ToScriptType());
|
||||
var parameterConverted = parameter == null ? new ScriptNull() : parameter.ToScriptType();
|
||||
innerEvaluator.Scope.CreateLocal(parameterSymbol, parameterConverted);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,7 +398,7 @@ namespace Upsilon.Evaluator
|
|||
case BoundBinaryOperator.OperatorKind.Or:
|
||||
return new ScriptBoolean((ScriptBoolean) left || (ScriptBoolean) right);
|
||||
default:
|
||||
throw new Exception("Invalid Binary Operator: " + e.Operator);
|
||||
throw new Exception("Invalid Binary Operator: " + e.Operator.Kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,20 @@ namespace Upsilon.Evaluator
|
|||
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope, this);
|
||||
}
|
||||
|
||||
public Script(BoundScript s, ScriptOptions options )
|
||||
{
|
||||
FileName = s.FileName;
|
||||
Options = options;
|
||||
Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError, s.FileName);
|
||||
|
||||
_bound = s;
|
||||
Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, s.Scope, this);
|
||||
|
||||
var staticScope = options.OverrideStaticScope ?? StaticScope.Scope;
|
||||
Scope = EvaluationScope.CreateWithGetOnlyParent(staticScope);
|
||||
Evaluator = Evaluator.CreateWithSetScope(Diagnostics, Scope, this);
|
||||
}
|
||||
|
||||
private Script(string fileName, string scriptString, Binder.Binder binder, Evaluator evaluator, ScriptOptions options)
|
||||
{
|
||||
ScriptString = new SourceText(scriptString);
|
||||
|
@ -75,6 +89,7 @@ namespace Upsilon.Evaluator
|
|||
return s;
|
||||
}
|
||||
|
||||
|
||||
internal void Parse()
|
||||
{
|
||||
_parsed = Parser.Parser.Parse(_scriptString, Diagnostics, Options.SaveDataComments);
|
||||
|
@ -98,6 +113,8 @@ namespace Upsilon.Evaluator
|
|||
|
||||
private static T Convert<T>(ScriptType t)
|
||||
{
|
||||
if (t == null)
|
||||
return default(T);
|
||||
if (typeof(T) == typeof(double))
|
||||
return (T)(object)System.Convert.ToDouble(t.ToCSharpObject());
|
||||
if (typeof(T) == typeof(long))
|
||||
|
|
|
@ -4,12 +4,11 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
public class ScriptLoader
|
||||
{
|
||||
public virtual string FilePath { get; } = "./";
|
||||
public virtual string ModulesPath { get; } = "./modules/";
|
||||
public virtual string FilePath { get; set; } = "./";
|
||||
public virtual string ModulesPath { get; set; } = "./modules/";
|
||||
|
||||
public virtual string LoadFile(string fileName)
|
||||
{
|
||||
var path = FilePath;
|
||||
var resolvedName = ResolveFileName(FilePath, fileName);
|
||||
if (File.Exists(resolvedName))
|
||||
{
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace Upsilon
|
|||
{
|
||||
if (options == null) options = DefaultOptions;
|
||||
var input = options.ScriptLoader.LoadFile(fileName);
|
||||
if (input == null)
|
||||
return null;
|
||||
var script = new Script(input,fileName, options);
|
||||
script.Parse();
|
||||
return script;
|
||||
|
@ -70,6 +72,12 @@ namespace Upsilon
|
|||
return script.Evaluate();
|
||||
}
|
||||
|
||||
public static object EvaluateScript(BoundScript input, ScriptOptions options = null)
|
||||
{
|
||||
var script = new Script(input, options);
|
||||
return script.Evaluate();
|
||||
}
|
||||
|
||||
public static T EvaluateFunction<T>(string input, string function, object[] parameters = null, ScriptOptions options = null)
|
||||
{
|
||||
var script = ParseInputAndEvaluate(input, options);
|
||||
|
|
Loading…
Reference in New Issue