Various changes and tweaks to run better

This commit is contained in:
Deukhoofd 2018-12-08 16:18:38 +01:00
parent f6947194b9
commit 43d9360145
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
15 changed files with 142 additions and 75 deletions

View File

@ -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)
{

View File

@ -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:

View File

@ -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;

View File

@ -0,0 +1,9 @@
using System;
namespace Upsilon.BaseTypes.UserData
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]
public class UpsilonHiddenAttribute : Attribute
{
}
}

View File

@ -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)

View File

@ -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))
{

View File

@ -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);
}
}

View File

@ -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.");
}
}
}
}

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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))

View File

@ -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))
{

View File

@ -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);