|
@@ -17,301 +17,300 @@ using Microsoft.CodeAnalysis.Scripting;
|
|
|
using Microsoft.CodeAnalysis.Scripting.Hosting;
|
|
|
using RoslynPad.Roslyn;
|
|
|
|
|
|
-namespace InABox.Scripting
|
|
|
+namespace InABox.Scripting;
|
|
|
+
|
|
|
+public class ScriptProperty : Dictionary<string, object>
|
|
|
{
|
|
|
- public class ScriptProperty : Dictionary<string, object>
|
|
|
+ public ScriptProperty(string name, object? value)
|
|
|
{
|
|
|
- public ScriptProperty(string name, object? value)
|
|
|
- {
|
|
|
- Name = name;
|
|
|
- Value = value;
|
|
|
- }
|
|
|
-
|
|
|
- public string Name { get; set; }
|
|
|
- public object? Value { get; set; }
|
|
|
+ Name = name;
|
|
|
+ Value = value;
|
|
|
}
|
|
|
|
|
|
- public class CompileException : Exception
|
|
|
- {
|
|
|
- public CompileException() : base("Unable to compile script!") { }
|
|
|
- }
|
|
|
+ public string Name { get; set; }
|
|
|
+ public object? Value { get; set; }
|
|
|
+}
|
|
|
|
|
|
- public class ScriptDocument : INotifyPropertyChanged
|
|
|
- {
|
|
|
- private string _result;
|
|
|
-
|
|
|
- private string _text = "";
|
|
|
- private bool? compiled;
|
|
|
- private object? obj;
|
|
|
+public class CompileException : Exception
|
|
|
+{
|
|
|
+ public CompileException() : base("Unable to compile script!") { }
|
|
|
+}
|
|
|
|
|
|
- private Type? type;
|
|
|
+public class ScriptDocument : INotifyPropertyChanged
|
|
|
+{
|
|
|
+ private string _result;
|
|
|
|
|
|
- static ScriptDocument()
|
|
|
- {
|
|
|
- DefaultAssemblies = new FluentList<Assembly>()
|
|
|
- .Add(typeof(object).Assembly)
|
|
|
- .Add(typeof(Regex).Assembly)
|
|
|
- .Add(typeof(List<>).Assembly)
|
|
|
- .Add(typeof(Enumerable).Assembly)
|
|
|
- .Add(typeof(Bitmap).Assembly)
|
|
|
- .Add(typeof(Expression).Assembly);
|
|
|
- }
|
|
|
+ private string _text = "";
|
|
|
+ private bool? compiled;
|
|
|
+ private object? obj;
|
|
|
|
|
|
+ private Type? type;
|
|
|
|
|
|
- public ScriptDocument(string text)
|
|
|
- {
|
|
|
- if (Host == null)
|
|
|
- Initialize();
|
|
|
- Text = text;
|
|
|
- Properties = new List<ScriptProperty>();
|
|
|
- }
|
|
|
+ static ScriptDocument()
|
|
|
+ {
|
|
|
+ DefaultAssemblies = new FluentList<Assembly>()
|
|
|
+ .Add(typeof(object).Assembly)
|
|
|
+ .Add(typeof(Regex).Assembly)
|
|
|
+ .Add(typeof(List<>).Assembly)
|
|
|
+ .Add(typeof(Enumerable).Assembly)
|
|
|
+ .Add(typeof(Bitmap).Assembly)
|
|
|
+ .Add(typeof(Expression).Assembly);
|
|
|
+ }
|
|
|
|
|
|
- public static RoslynHost Host { get; private set; }
|
|
|
|
|
|
- public static FluentList<Assembly> DefaultAssemblies { get; }
|
|
|
+ public ScriptDocument(string text)
|
|
|
+ {
|
|
|
+ if (Host == null)
|
|
|
+ Initialize();
|
|
|
+ Text = text;
|
|
|
+ Properties = new List<ScriptProperty>();
|
|
|
+ }
|
|
|
|
|
|
- public Script<object> Script { get; private set; }
|
|
|
+ public static RoslynHost Host { get; private set; }
|
|
|
|
|
|
- public string Text
|
|
|
- {
|
|
|
- get => _text;
|
|
|
- set => SetProperty(ref _text, value);
|
|
|
- }
|
|
|
+ public static FluentList<Assembly> DefaultAssemblies { get; }
|
|
|
|
|
|
- public DocumentId Id { get; set; }
|
|
|
+ public Script<object> Script { get; private set; }
|
|
|
|
|
|
- public string Result
|
|
|
- {
|
|
|
- get => _result;
|
|
|
- private set => SetProperty(ref _result, value);
|
|
|
- }
|
|
|
+ public string Text
|
|
|
+ {
|
|
|
+ get => _text;
|
|
|
+ set => SetProperty(ref _text, value);
|
|
|
+ }
|
|
|
|
|
|
- private static MethodInfo HasSubmissionResult { get; } =
|
|
|
- typeof(Compilation).GetMethod(nameof(HasSubmissionResult), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
- ?? throw new NullReferenceException();
|
|
|
+ public DocumentId Id { get; set; }
|
|
|
|
|
|
- private static PrintOptions PrintOptions { get; } = new() { MemberDisplayFormat = MemberDisplayFormat.SeparateLines };
|
|
|
+ public string Result
|
|
|
+ {
|
|
|
+ get => _result;
|
|
|
+ private set => SetProperty(ref _result, value);
|
|
|
+ }
|
|
|
|
|
|
- public List<ScriptProperty> Properties { get; }
|
|
|
+ private static MethodInfo HasSubmissionResult { get; } =
|
|
|
+ typeof(Compilation).GetMethod(nameof(HasSubmissionResult), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
+ ?? throw new NullReferenceException();
|
|
|
|
|
|
- public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
+ private static PrintOptions PrintOptions { get; } = new() { MemberDisplayFormat = MemberDisplayFormat.SeparateLines };
|
|
|
|
|
|
- private static IEnumerable<MetadataReference> CompilationReferences;
|
|
|
+ public List<ScriptProperty> Properties { get; }
|
|
|
|
|
|
- public static void Initialize()
|
|
|
- {
|
|
|
- var typelist = CoreUtils.TypeList(
|
|
|
- AppDomain.CurrentDomain.GetAssemblies(),
|
|
|
- x =>
|
|
|
- x.GetTypeInfo().IsClass
|
|
|
- && !x.GetTypeInfo().IsGenericType
|
|
|
- && x.GetTypeInfo().IsSubclassOf(typeof(BaseObject))).ToList();
|
|
|
- for (var i = typelist.Count - 1; i > -1; i--) // var type in typelist)
|
|
|
- {
|
|
|
- var type = typelist[i];
|
|
|
- var module = type.Assembly.Modules.FirstOrDefault();
|
|
|
- if (module != null && !module.FullyQualifiedName.Equals("<Unknown>"))
|
|
|
- DefaultAssemblies.Add(type.Assembly);
|
|
|
- else
|
|
|
- typelist.RemoveAt(i);
|
|
|
- }
|
|
|
+ public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
|
|
- var references = Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "refs"), "*.dll")
|
|
|
- .Select(x => MetadataReference.CreateFromFile(x)).ToArray();
|
|
|
-
|
|
|
- var files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll").Where(
|
|
|
- x => !Path.GetFileName(x).ToLower().StartsWith("gsdll")
|
|
|
- && !Path.GetFileName(x).ToLower().StartsWith("pdfium")
|
|
|
- && !Path.GetFileName(x).ToLower().StartsWith("ikvm-native")
|
|
|
- && !Path.GetFileName(x).ToLower().StartsWith("sqlite.interop")
|
|
|
- && !Path.GetFileName(x).ToLower().StartsWith("microsoft.codeanalysis")
|
|
|
- );
|
|
|
-
|
|
|
- var hostReferences = RoslynHostReferences.NamespaceDefault.With(
|
|
|
- typeNamespaceImports: typelist
|
|
|
- //, assemblyReferences: DefaultAssemblies
|
|
|
- , assemblyPathReferences: files,
|
|
|
- references: references
|
|
|
- );
|
|
|
- CompilationReferences = RoslynHostReferences.NamespaceDefault.With(
|
|
|
- typeNamespaceImports: typelist
|
|
|
- , assemblyReferences: DefaultAssemblies
|
|
|
- , assemblyPathReferences: files
|
|
|
- ).GetReferences();
|
|
|
-
|
|
|
- Host = new RoslynHost(
|
|
|
- DefaultAssemblies.ToArray(),
|
|
|
- hostReferences
|
|
|
- );
|
|
|
- }
|
|
|
+ private static IEnumerable<MetadataReference> CompilationReferences;
|
|
|
|
|
|
- public bool Compile()
|
|
|
+ public static void Initialize()
|
|
|
+ {
|
|
|
+ var typelist = CoreUtils.TypeList(
|
|
|
+ AppDomain.CurrentDomain.GetAssemblies(),
|
|
|
+ x =>
|
|
|
+ x.GetTypeInfo().IsClass
|
|
|
+ && !x.GetTypeInfo().IsGenericType
|
|
|
+ && x.GetTypeInfo().IsSubclassOf(typeof(BaseObject))).ToList();
|
|
|
+ for (var i = typelist.Count - 1; i > -1; i--) // var type in typelist)
|
|
|
{
|
|
|
- Result = null;
|
|
|
- compiled = null;
|
|
|
+ var type = typelist[i];
|
|
|
+ var module = type.Assembly.Modules.FirstOrDefault();
|
|
|
+ if (module != null && !module.FullyQualifiedName.Equals("<Unknown>"))
|
|
|
+ DefaultAssemblies.Add(type.Assembly);
|
|
|
+ else
|
|
|
+ typelist.RemoveAt(i);
|
|
|
+ }
|
|
|
|
|
|
- Script = CSharpScript.Create(Text, ScriptOptions.Default
|
|
|
- .AddReferences(CompilationReferences)
|
|
|
- .AddImports(Host.DefaultImports));
|
|
|
+ var references = Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "refs"), "*.dll")
|
|
|
+ .Select(x => MetadataReference.CreateFromFile(x)).ToArray();
|
|
|
+
|
|
|
+ var files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll").Where(
|
|
|
+ x => !Path.GetFileName(x).ToLower().StartsWith("gsdll")
|
|
|
+ && !Path.GetFileName(x).ToLower().StartsWith("pdfium")
|
|
|
+ && !Path.GetFileName(x).ToLower().StartsWith("ikvm-native")
|
|
|
+ && !Path.GetFileName(x).ToLower().StartsWith("sqlite.interop")
|
|
|
+ && !Path.GetFileName(x).ToLower().StartsWith("microsoft.codeanalysis")
|
|
|
+ );
|
|
|
+
|
|
|
+ var hostReferences = RoslynHostReferences.NamespaceDefault.With(
|
|
|
+ typeNamespaceImports: typelist
|
|
|
+ //, assemblyReferences: DefaultAssemblies
|
|
|
+ , assemblyPathReferences: files,
|
|
|
+ references: references
|
|
|
+ );
|
|
|
+ CompilationReferences = RoslynHostReferences.NamespaceDefault.With(
|
|
|
+ typeNamespaceImports: typelist
|
|
|
+ , assemblyReferences: DefaultAssemblies
|
|
|
+ , assemblyPathReferences: files
|
|
|
+ ).GetReferences();
|
|
|
+
|
|
|
+ Host = new RoslynHost(
|
|
|
+ DefaultAssemblies.ToArray(),
|
|
|
+ hostReferences
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
- var compilation = Script.GetCompilation();
|
|
|
- var hasResult = (bool)HasSubmissionResult.Invoke(compilation, null);
|
|
|
- var diagnostics = Script.Compile();
|
|
|
- if (diagnostics.Any(t => t.Severity == DiagnosticSeverity.Error))
|
|
|
- {
|
|
|
- var result = new List<string>();
|
|
|
- var errors = diagnostics.Select(FormatObject).Where(x => x.StartsWith("CSDiagnostic("));
|
|
|
- foreach (var error in errors)
|
|
|
- result.Add(
|
|
|
- error.Split(new[] { Environment.NewLine }, StringSplitOptions.None).First().Replace("CSDiagnostic(", "").Replace(") {", ""));
|
|
|
- Result = string.Join(Environment.NewLine, result);
|
|
|
- return false;
|
|
|
- }
|
|
|
+ public bool Compile()
|
|
|
+ {
|
|
|
+ Result = null;
|
|
|
+ compiled = null;
|
|
|
|
|
|
- return true;
|
|
|
- }
|
|
|
+ Script = CSharpScript.Create(Text, ScriptOptions.Default
|
|
|
+ .AddReferences(CompilationReferences)
|
|
|
+ .AddImports(Host.DefaultImports));
|
|
|
|
|
|
- public void SetValue(string name, object value)
|
|
|
+ var compilation = Script.GetCompilation();
|
|
|
+ var hasResult = (bool)HasSubmissionResult.Invoke(compilation, null);
|
|
|
+ var diagnostics = Script.Compile();
|
|
|
+ if (diagnostics.Any(t => t.Severity == DiagnosticSeverity.Error))
|
|
|
{
|
|
|
- var prop = Properties.FirstOrDefault(x => x.Name.Equals(name));
|
|
|
- if (prop == null)
|
|
|
- Properties.Add(new ScriptProperty(name, value));
|
|
|
- else
|
|
|
- prop.Value = value;
|
|
|
+ var result = new List<string>();
|
|
|
+ var errors = diagnostics.Select(FormatObject).Where(x => x.StartsWith("CSDiagnostic("));
|
|
|
+ foreach (var error in errors)
|
|
|
+ result.Add(
|
|
|
+ error.Split(new[] { Environment.NewLine }, StringSplitOptions.None).First().Replace("CSDiagnostic(", "").Replace(") {", ""));
|
|
|
+ Result = string.Join(Environment.NewLine, result);
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- public object? GetValue(string name, object? defaultvalue = null)
|
|
|
- {
|
|
|
- var prop = Properties.FirstOrDefault(x => x.Name.Equals(name));
|
|
|
- return prop != null ? prop.Value : defaultvalue;
|
|
|
- }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- private Type? GetClassType(string className = "Module")
|
|
|
+ public void SetValue(string name, object value)
|
|
|
+ {
|
|
|
+ var prop = Properties.FirstOrDefault(x => x.Name.Equals(name));
|
|
|
+ if (prop == null)
|
|
|
+ Properties.Add(new ScriptProperty(name, value));
|
|
|
+ else
|
|
|
+ prop.Value = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ public object? GetValue(string name, object? defaultvalue = null)
|
|
|
+ {
|
|
|
+ var prop = Properties.FirstOrDefault(x => x.Name.Equals(name));
|
|
|
+ return prop != null ? prop.Value : defaultvalue;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Type? GetClassType(string className = "Module")
|
|
|
+ {
|
|
|
+ if (!compiled.HasValue)
|
|
|
{
|
|
|
- if (!compiled.HasValue)
|
|
|
+ compiled = false;
|
|
|
+ var stream = new MemoryStream();
|
|
|
+ var emitResult = Script.GetCompilation().Emit(stream);
|
|
|
+ if (emitResult.Success)
|
|
|
{
|
|
|
- compiled = false;
|
|
|
- var stream = new MemoryStream();
|
|
|
- var emitResult = Script.GetCompilation().Emit(stream);
|
|
|
- if (emitResult.Success)
|
|
|
+ var asm = Assembly.Load(stream.ToArray());
|
|
|
+ type = asm.GetTypes().Where(x => x.Name.Equals(className)).FirstOrDefault();
|
|
|
+ if (type != null)
|
|
|
{
|
|
|
- var asm = Assembly.Load(stream.ToArray());
|
|
|
- type = asm.GetTypes().Where(x => x.Name.Equals(className)).FirstOrDefault();
|
|
|
- if (type != null)
|
|
|
- {
|
|
|
- obj = Activator.CreateInstance(type);
|
|
|
- compiled = true;
|
|
|
- }
|
|
|
+ obj = Activator.CreateInstance(type);
|
|
|
+ compiled = true;
|
|
|
}
|
|
|
}
|
|
|
- return type;
|
|
|
}
|
|
|
+ return type;
|
|
|
+ }
|
|
|
|
|
|
- public object? GetObject(string className = "Module")
|
|
|
+ public object? GetObject(string className = "Module")
|
|
|
+ {
|
|
|
+ GetClassType(className);
|
|
|
+ return obj;
|
|
|
+ }
|
|
|
+
|
|
|
+ public MethodInfo? GetMethod(string className = "Module", string methodName = "Execute")
|
|
|
+ {
|
|
|
+ var type = GetClassType(className);
|
|
|
+ if (compiled == true && type != null)
|
|
|
{
|
|
|
- GetClassType(className);
|
|
|
- return obj;
|
|
|
+ return type.GetMethod(methodName);
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- public MethodInfo? GetMethod(string className = "Module", string methodName = "Execute")
|
|
|
+ public bool Execute(string classname = "Module", string methodname = "Execute", object[]? parameters = null, bool defaultResult = false)
|
|
|
+ {
|
|
|
+ var result = defaultResult;
|
|
|
+
|
|
|
+ var type = GetClassType(classname);
|
|
|
+ var obj = GetObject(classname);
|
|
|
+ var method = GetMethod(classname, methodname);
|
|
|
+
|
|
|
+ if (compiled == true && type != null && method != null)
|
|
|
{
|
|
|
- var type = GetClassType(className);
|
|
|
- if (compiled == true && type != null)
|
|
|
+ foreach (var property in Properties)
|
|
|
+ {
|
|
|
+ var prop = type.GetProperty(property.Name);
|
|
|
+ prop?.SetValue(obj, property.Value);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (method.ReturnType == typeof(bool))
|
|
|
{
|
|
|
- return type.GetMethod(methodName);
|
|
|
+ result = (bool)(method.Invoke(obj, parameters ?? Array.Empty<object>()) ?? false);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- return null;
|
|
|
+ method.Invoke(obj, parameters ?? Array.Empty<object>());
|
|
|
+ result = true;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- public bool Execute(string classname = "Module", string methodname = "Execute", object[]? parameters = null, bool defaultResult = false)
|
|
|
- {
|
|
|
- var result = defaultResult;
|
|
|
-
|
|
|
- var type = GetClassType(classname);
|
|
|
- var obj = GetObject(classname);
|
|
|
- var method = GetMethod(classname, methodname);
|
|
|
|
|
|
- if (compiled == true && type != null && method != null)
|
|
|
+ if (result)
|
|
|
{
|
|
|
foreach (var property in Properties)
|
|
|
{
|
|
|
var prop = type.GetProperty(property.Name);
|
|
|
- prop?.SetValue(obj, property.Value);
|
|
|
- }
|
|
|
-
|
|
|
- if (method.ReturnType == typeof(bool))
|
|
|
- {
|
|
|
- result = (bool)(method.Invoke(obj, parameters ?? Array.Empty<object>()) ?? false);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- method.Invoke(obj, parameters ?? Array.Empty<object>());
|
|
|
- result = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (result)
|
|
|
- {
|
|
|
- foreach (var property in Properties)
|
|
|
- {
|
|
|
- var prop = type.GetProperty(property.Name);
|
|
|
- if (prop != null)
|
|
|
- property.Value = prop.GetValue(obj);
|
|
|
- }
|
|
|
+ if (prop != null)
|
|
|
+ property.Value = prop.GetValue(obj);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return result;
|
|
|
}
|
|
|
|
|
|
- private static string FormatException(Exception ex)
|
|
|
- {
|
|
|
- return CSharpObjectFormatter.Instance.FormatException(ex);
|
|
|
- }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
- private static string FormatObject(object o)
|
|
|
+ private static string FormatException(Exception ex)
|
|
|
+ {
|
|
|
+ return CSharpObjectFormatter.Instance.FormatException(ex);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static string FormatObject(object o)
|
|
|
+ {
|
|
|
+ return CSharpObjectFormatter.Instance.FormatObject(o, PrintOptions);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
|
|
|
+ {
|
|
|
+ if (!EqualityComparer<T>.Default.Equals(field, value))
|
|
|
{
|
|
|
- return CSharpObjectFormatter.Instance.FormatObject(o, PrintOptions);
|
|
|
+ field = value;
|
|
|
+ // ReSharper disable once ExplicitCallerInfoArgument
|
|
|
+ OnPropertyChanged(propertyName);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
|
|
|
- {
|
|
|
- if (!EqualityComparer<T>.Default.Equals(field, value))
|
|
|
- {
|
|
|
- field = value;
|
|
|
- // ReSharper disable once ExplicitCallerInfoArgument
|
|
|
- OnPropertyChanged(propertyName);
|
|
|
- return true;
|
|
|
- }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- return false;
|
|
|
- }
|
|
|
+ protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
|
+ {
|
|
|
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
+ }
|
|
|
|
|
|
- protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
|
+ public static bool RunCustomModule(DataModel model, Dictionary<string, object[]> selected, string code)
|
|
|
+ {
|
|
|
+ var script = new ScriptDocument(code);
|
|
|
+ if (!script.Compile())
|
|
|
{
|
|
|
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
+ throw new CompileException();
|
|
|
}
|
|
|
|
|
|
- public static bool RunCustomModule(DataModel model, Dictionary<string, object[]> selected, string code)
|
|
|
- {
|
|
|
- var script = new ScriptDocument(code);
|
|
|
- if (!script.Compile())
|
|
|
- {
|
|
|
- throw new CompileException();
|
|
|
- }
|
|
|
-
|
|
|
- script.SetValue("Data", selected);
|
|
|
- script.SetValue("Model", model);
|
|
|
+ script.SetValue("Data", selected);
|
|
|
+ script.SetValue("Model", model);
|
|
|
|
|
|
- script.Execute(methodname: "BeforeLoad");
|
|
|
- var tableNames = model.DefaultTableNames.ToList();
|
|
|
- script.Execute(methodname: "CheckTables", parameters: new[] { tableNames });
|
|
|
+ script.Execute(methodname: "BeforeLoad");
|
|
|
+ var tableNames = model.DefaultTableNames.ToList();
|
|
|
+ script.Execute(methodname: "CheckTables", parameters: new[] { tableNames });
|
|
|
|
|
|
- model.LoadModel(tableNames);
|
|
|
+ model.LoadModel(tableNames);
|
|
|
|
|
|
- return script.Execute();
|
|
|
- }
|
|
|
+ return script.Execute();
|
|
|
}
|
|
|
}
|