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) 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>(); var objects = new List<object>();
if (_passScriptReference) if (_passScriptReference)
objects.Add(script); objects.Add(script);
@ -62,19 +52,11 @@ namespace Upsilon.BaseTypes.ScriptFunction
objects.AddRange(_directTypeManipulation objects.AddRange(_directTypeManipulation
? variables.Select(x => (object) x).ToList() ? variables.Select(x => (object) x).ToList()
: variables.Select(x => x.ToCSharpObject()).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; object result;
try try
{ {
result = method.Invoke(_object, objects.ToArray()); result = _object.GetType().InvokeMember(_method.Name, BindingFlags.InvokeMethod, System.Type.DefaultBinder,
_object, objects.ToArray());
} }
catch (TargetInvocationException e) catch (TargetInvocationException e)
{ {

View File

@ -5,6 +5,7 @@ using Upsilon.BaseTypes.Number;
using Upsilon.BaseTypes.ScriptFunction; using Upsilon.BaseTypes.ScriptFunction;
using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.BaseTypes.ScriptTypeInterfaces;
using Upsilon.BaseTypes.UserData; using Upsilon.BaseTypes.UserData;
using Upsilon.Text;
namespace Upsilon.BaseTypes namespace Upsilon.BaseTypes
{ {
@ -19,6 +20,8 @@ namespace Upsilon.BaseTypes
return new ScriptBoolean(b); return new ScriptBoolean(b);
case int i: case int i:
return new ScriptNumberLong(i); return new ScriptNumberLong(i);
case short s:
return new ScriptNumberLong(s);
case long i: case long i:
return new ScriptNumberLong(i); return new ScriptNumberLong(i);
case float f: case float f:

View File

@ -5,10 +5,10 @@ namespace Upsilon.BaseTypes.UserData
{ {
internal sealed class GenericUserData : ScriptType, IUserData internal sealed class GenericUserData : ScriptType, IUserData
{ {
public GenericUserData(object dictionary) public GenericUserData(object obj)
{ {
Value = dictionary; Value = obj;
_typeInfo = UserDataTypeHandler.GetTypeInfo(dictionary.GetType()); _typeInfo = UserDataTypeHandler.GetTypeInfo(obj.GetType());
} }
public override Type Type => Type.UserData; 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 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 class UpsilonUserDataAttribute : Attribute
{ {
public UpsilonUserDataAttribute(string name) public UpsilonUserDataAttribute(string name)

View File

@ -38,6 +38,8 @@ namespace Upsilon.BaseTypes.UserData
public UserDataMethodParameter(ParameterInfo info) public UserDataMethodParameter(ParameterInfo info)
{ {
Type = info.ParameterType; Type = info.ParameterType;
if (Type.IsGenericType)
Type = Type.GetGenericTypeDefinition();
IsOptional = info.IsOptional; IsOptional = info.IsOptional;
} }
@ -89,6 +91,7 @@ namespace Upsilon.BaseTypes.UserData
break; break;
} }
var parameter = parameterTypes[index]; var parameter = parameterTypes[index];
if (parameter.IsGenericType) parameter = parameter.GetGenericTypeDefinition();
if (userDataMethodParameter.Type != parameter && if (userDataMethodParameter.Type != parameter &&
!userDataMethodParameter.Type.IsAssignableFrom(parameter)) !userDataMethodParameter.Type.IsAssignableFrom(parameter))
{ {

View File

@ -10,12 +10,20 @@ namespace Upsilon.BaseTypes.UserData
{ {
public UserDataType(System.Type type) public UserDataType(System.Type type)
{ {
if (type.IsGenericType)
{
type = type.GetGenericTypeDefinition();
}
Type = type; Type = type;
Variables = type.GetFields().ToDictionary(x => x.Name.ToLowerInvariant(), x => x); Variables = type.GetFields().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
Properties = type.GetProperties().ToDictionary(x => x.Name.ToLowerInvariant(), x => x); Properties = type.GetProperties().ToDictionary(x => x.Name.ToLowerInvariant(), x => x);
Methods = new Dictionary<string, UserDataMethod>(); Methods = new Dictionary<string, UserDataMethod>();
foreach (var methodInfo in type.GetMethods()) foreach (var methodInfo in type.GetMethods())
{ {
var hiddenAttribute = methodInfo.GetCustomAttribute(typeof(UpsilonHiddenAttribute));
if (hiddenAttribute != null)
continue;
var commonName = methodInfo.Name.ToLowerInvariant(); var commonName = methodInfo.Name.ToLowerInvariant();
var attribute = methodInfo.GetCustomAttribute(typeof(ScriptFunctionAttribute)); var attribute = methodInfo.GetCustomAttribute(typeof(ScriptFunctionAttribute));
if (attribute is ScriptFunctionAttribute sfa ) 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) 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"); return (null, true, "Invalid Type");
member = member.ToLowerInvariant(); member = member.ToLowerInvariant();
if (Variables.TryGetValue(member, out var info)) if (Variables.TryGetValue(member, out var info))
@ -93,6 +104,12 @@ namespace Upsilon.BaseTypes.UserData
return (new ScriptNull(), true); 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); return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToScriptType(), false);
} }
public (ScriptType Type, bool Failed) UnaryOperator(object value, ScriptType par1, OperatorType op) public (ScriptType Type, bool Failed) UnaryOperator(object value, ScriptType par1, OperatorType op)
@ -103,6 +120,12 @@ namespace Upsilon.BaseTypes.UserData
return (new ScriptNull(), true); 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); return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToScriptType(), false);
} }
} }

View File

@ -1,19 +1,23 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using Upsilon.BoundTypes; using Upsilon.BoundTypes;
using Upsilon.Exceptions;
using Upsilon.StandardLibraries; using Upsilon.StandardLibraries;
using Upsilon.Text;
namespace Upsilon.BaseTypes.UserData namespace Upsilon.BaseTypes.UserData
{ {
public static class UserDataTypeHandler 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) public static void LoadType(System.Type t, string name)
{ {
var info = new UserDataType(t); var info = new UserDataType(t);
Types.Add(t, info); Types.AddOrUpdate(t, info, (type, dataType) => dataType);
UserDataBoundTypeDefinition boundType; UserDataBoundTypeDefinition boundType;
if (t.IsEnum) if (t.IsEnum)
{ {
@ -55,7 +59,14 @@ namespace Upsilon.BaseTypes.UserData
internal static UserDataType GetTypeInfo(System.Type t) 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; return null;
} }
if (t1.IsGenericType) t1 = t1.GetGenericTypeDefinition();
if (t2.IsGenericType) t2 = t2.GetGenericTypeDefinition();
foreach (var operatorMethod in m) foreach (var operatorMethod in m)
{ {

View File

@ -316,10 +316,12 @@ namespace Upsilon.Binder
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) indexerVariable).BoundTypeDefinition; (UserDataBoundTypeDefinition) ((UserDataVariableSymbol) indexerVariable).BoundTypeDefinition;
var bDefProperty = parent.Properties[fullStopIndexExpression.Index.ToLowerInvariant()]; var bDefProperty = parent.Properties[fullStopIndexExpression.Index.ToLowerInvariant()];
var boundDef = BoundTypeHandler.GetTypeDefinition(bDefProperty.ActualType); var boundDef = BoundTypeHandler.GetTypeDefinition(bDefProperty.ActualType);
if (boundDef != null)
{
return new UserDataVariableSymbol(fullStopIndexExpression.Index, boundDef, parent); return new UserDataVariableSymbol(fullStopIndexExpression.Index, boundDef, parent);
} }
}
if (indexerVariable.Type == Type.Unknown) else if (indexerVariable.Type == Type.Unknown)
{ {
if (indexerVariable is UserDataVariableSymbol funcSymbol) if (indexerVariable is UserDataVariableSymbol funcSymbol)
{ {
@ -335,8 +337,7 @@ namespace Upsilon.Binder
return new VariableSymbol(fullStopIndexExpression.Index, Type.Unknown, true); return new VariableSymbol(fullStopIndexExpression.Index, Type.Unknown, true);
} }
} }
else if (expression.Kind == BoundKind.BoundFunctionCallExpression)
if (expression.Kind == BoundKind.BoundFunctionCallExpression)
{ {
return new VariableSymbol("", expression.Type, true); return new VariableSymbol("", expression.Type, true);
} }

View File

@ -1,5 +1,5 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
@ -7,33 +7,29 @@ namespace Upsilon.BoundTypes
{ {
public static class BoundTypeHandler public static class BoundTypeHandler
{ {
private static readonly Dictionary<string, BoundTypeDefinition> DefaultTypeDefinitions = private static void AddDefaults(ConcurrentDictionary<string, BoundTypeDefinition> dic)
new Dictionary<string, BoundTypeDefinition>
{ {
{"string", new BoundTypeDefinition(Type.String, typeof(string))}, dic.TryAdd("string", new BoundTypeDefinition(Type.String, typeof(string)));
{ dic.TryAdd("number", new BoundTypeDefinition(Type.Number,
"number", new[] {typeof(int), typeof(long), typeof(float), typeof(double)}));
new BoundTypeDefinition(Type.Number, dic.TryAdd("bool", new BoundTypeDefinition(Type.Boolean, typeof(bool)));
new[] {typeof(int), typeof(long), typeof(float), typeof(double)}) dic.TryAdd("table", new BoundTypeDefinition(Type.Table, typeof(IEnumerator)));
}, dic.TryAdd("function", new BoundTypeDefinition(Type.Function, new System.Type[0]));
{"bool", new BoundTypeDefinition(Type.Boolean, typeof(bool))}, }
{"table", new BoundTypeDefinition(Type.Table, typeof(IEnumerator))},
{"function", new BoundTypeDefinition(Type.Function, new System.Type[0])},
};
private static Dictionary<string, BoundTypeDefinition> _typeDefinitions = private static readonly ConcurrentDictionary<string, BoundTypeDefinition> TypeDefinitions = Reset();
new Dictionary<string, BoundTypeDefinition>(DefaultTypeDefinitions);
public static void Reset() public static ConcurrentDictionary<string, BoundTypeDefinition> Reset()
{ {
_typeDefinitions = var dic = new ConcurrentDictionary<string, BoundTypeDefinition>();
new Dictionary<string, BoundTypeDefinition>(DefaultTypeDefinitions); AddDefaults(dic);
return dic;
} }
public static BoundTypeDefinition GetTypeDefinition(string key) public static BoundTypeDefinition GetTypeDefinition(string key)
{ {
var normalizedName = key.ToLowerInvariant(); var normalizedName = key.ToLowerInvariant();
if (_typeDefinitions.TryGetValue(normalizedName, out var bt)) if (TypeDefinitions.TryGetValue(normalizedName, out var bt))
{ {
return bt; return bt;
} }
@ -42,20 +38,13 @@ namespace Upsilon.BoundTypes
public static BoundTypeDefinition GetTypeDefinition(System.Type type) 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) public static void LoadUserDataTypeDefinition(UserDataBoundTypeDefinition def)
{ {
var key = def.Name.ToLowerInvariant(); var key = def.Name.ToLowerInvariant();
if (_typeDefinitions.ContainsKey(key)) TypeDefinitions.AddOrUpdate(key, def, (s, definition) => definition);
{
_typeDefinitions[key] = def;
}
else
{
_typeDefinitions.Add(key, def);
}
} }
} }
} }

View File

@ -75,9 +75,26 @@ namespace Upsilon.Evaluator
{ {
for (var index = 0; index < parameters.Length; index++) for (var index = 0; index < parameters.Length; index++)
{ {
var parameter = parameters[index]; object parameter;
var parameterSymbol = (UserDataVariableSymbol)function.Parameters[index].VariableSymbol; if (index < parameters.Length)
if (parameterSymbol.BoundTypeDefinition != null) {
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; bool isCompatible = false;
var parameterType = parameter.GetType(); 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: case BoundBinaryOperator.OperatorKind.Or:
return new ScriptBoolean((ScriptBoolean) left || (ScriptBoolean) right); return new ScriptBoolean((ScriptBoolean) left || (ScriptBoolean) right);
default: 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); 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) private Script(string fileName, string scriptString, Binder.Binder binder, Evaluator evaluator, ScriptOptions options)
{ {
ScriptString = new SourceText(scriptString); ScriptString = new SourceText(scriptString);
@ -75,6 +89,7 @@ namespace Upsilon.Evaluator
return s; return s;
} }
internal void Parse() internal void Parse()
{ {
_parsed = Parser.Parser.Parse(_scriptString, Diagnostics, Options.SaveDataComments); _parsed = Parser.Parser.Parse(_scriptString, Diagnostics, Options.SaveDataComments);
@ -98,6 +113,8 @@ namespace Upsilon.Evaluator
private static T Convert<T>(ScriptType t) private static T Convert<T>(ScriptType t)
{ {
if (t == null)
return default(T);
if (typeof(T) == typeof(double)) if (typeof(T) == typeof(double))
return (T)(object)System.Convert.ToDouble(t.ToCSharpObject()); return (T)(object)System.Convert.ToDouble(t.ToCSharpObject());
if (typeof(T) == typeof(long)) if (typeof(T) == typeof(long))

View File

@ -4,12 +4,11 @@ namespace Upsilon.Evaluator
{ {
public class ScriptLoader public class ScriptLoader
{ {
public virtual string FilePath { get; } = "./"; public virtual string FilePath { get; set; } = "./";
public virtual string ModulesPath { get; } = "./modules/"; public virtual string ModulesPath { get; set; } = "./modules/";
public virtual string LoadFile(string fileName) public virtual string LoadFile(string fileName)
{ {
var path = FilePath;
var resolvedName = ResolveFileName(FilePath, fileName); var resolvedName = ResolveFileName(FilePath, fileName);
if (File.Exists(resolvedName)) if (File.Exists(resolvedName))
{ {

View File

@ -19,6 +19,8 @@ namespace Upsilon
{ {
if (options == null) options = DefaultOptions; if (options == null) options = DefaultOptions;
var input = options.ScriptLoader.LoadFile(fileName); var input = options.ScriptLoader.LoadFile(fileName);
if (input == null)
return null;
var script = new Script(input,fileName, options); var script = new Script(input,fileName, options);
script.Parse(); script.Parse();
return script; return script;
@ -70,6 +72,12 @@ namespace Upsilon
return script.Evaluate(); 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) public static T EvaluateFunction<T>(string input, string function, object[] parameters = null, ScriptOptions options = null)
{ {
var script = ParseInputAndEvaluate(input, options); var script = ParseInputAndEvaluate(input, options);