1using Microsoft.CodeAnalysis.Emit;
3using System.Collections.Generic;
5using System.Reflection;
7using System.Threading.Tasks;
69 if (!(
Arguments[i++].AssociatedObjectValue is Type Type))
72 Dictionary<string, bool> Dependencies =
new Dictionary<string, bool>()
74 { GetLocation(typeof(
object)),
true },
75 { Path.Combine(Path.GetDirectoryName(GetLocation(typeof(
object))),
"System.Runtime.dll"),
true },
76 { Path.Combine(Path.GetDirectoryName(GetLocation(typeof(Encoding))),
"System.Text.Encoding.dll"),
true },
77 { Path.Combine(Path.GetDirectoryName(GetLocation(typeof(MemoryStream))),
"System.IO.dll"),
true },
78 { Path.Combine(Path.GetDirectoryName(GetLocation(typeof(MemoryStream))),
"System.Runtime.Extensions.dll"),
true },
79 { Path.Combine(Path.GetDirectoryName(GetLocation(typeof(Task))),
"System.Threading.Tasks.dll"),
true },
80 { Path.Combine(Path.GetDirectoryName(GetLocation(typeof(Dictionary<string, object>))),
"System.Collections.dll"),
true },
81 { GetLocation(typeof(
Types)),
true },
83 { GetLocation(typeof(
Callback)),
true }
86 Dependencies[GetLocation(Type)] =
true;
90 if (!(
Arguments[i++].AssociatedObjectValue is Type TArg1))
94 Dependencies[GetLocation(TArg1)] =
true;
96 Type = Type.MakeGenericType(TArg1);
99 if (!delegateTypeInfo.IsAssignableFrom(Type.GetTypeInfo()))
105 Type ScriptProxyType;
107 lock (scriptProxyTypes)
109 if (!scriptProxyTypes.TryGetValue(Type, out ScriptProxyType))
111 Type ReturnType =
null;
112 ParameterInfo[] Parameters =
null;
114 foreach (MethodInfo MI
in Type.GetRuntimeMethods())
116 if (MI.Name ==
"Invoke")
118 ReturnType = MI.ReturnType;
119 Parameters = MI.GetParameters();
124 if (ReturnType is
null || Parameters is
null)
127 bool IsAsync = taskTypeInfo.IsAssignableFrom(ReturnType.GetTypeInfo());
129 string ClassTypeName = Type.Name.Replace(
"`",
"_GT_");
130 string ReferenceTypeName = ClassTypeName;
131 Type[] TypeArguments = Type.IsConstructedGenericType ? Type.GenericTypeArguments :
null;
132 int j, d = TypeArguments?.Length ?? 0;
133 StringBuilder sb =
new StringBuilder();
136 for (j = 0; j < d; j++)
137 ClassTypeName = ClassTypeName.Replace(
"GT_" + (j + 1).ToString(), TypeArguments[j].FullName.Replace(
".",
"_"));
139 StringBuilder CSharp =
new StringBuilder();
141 CSharp.AppendLine(
"using System;");
142 CSharp.AppendLine(
"using Waher.Script;");
143 CSharp.AppendLine(
"using Waher.Script.Abstraction.Elements;");
144 CSharp.AppendLine(
"using Waher.Script.Data.Functions;");
145 CSharp.AppendLine(
"using Waher.Script.Model;");
147 CSharp.Append(
"namespace ");
148 CSharp.Append(Type.Namespace);
149 CSharp.AppendLine(
".ScriptCallbacks");
150 CSharp.AppendLine(
"{");
151 CSharp.Append(
"\tpublic class ScriptProxy");
152 CSharp.Append(ClassTypeName);
153 CSharp.Append(
" : ScriptProxy<");
157 Type GenericType = Type.GetGenericTypeDefinition();
158 s = GenericType.FullName;
162 s = s.Substring(0, j);
167 for (j = 0; j < d; j++)
172 sb.Append(TypeArguments[j].FullName);
177 ReferenceTypeName = sb.ToString();
178 CSharp.Append(ReferenceTypeName);
182 CSharp.Append(Type.FullName);
184 CSharp.AppendLine(
">");
185 CSharp.AppendLine(
"\t{");
186 CSharp.Append(
"\t\tpublic ScriptProxy");
187 CSharp.Append(ClassTypeName);
188 CSharp.AppendLine(
"(ILambdaExpression Lambda, Variables Variables)");
189 CSharp.AppendLine(
"\t\t\t: base(Lambda, Variables)");
190 CSharp.AppendLine(
"\t\t{");
191 CSharp.AppendLine(
"\t\t}");
193 CSharp.Append(
"\t\tpublic override ");
194 CSharp.Append(ReferenceTypeName);
195 CSharp.AppendLine(
" GetCallbackFunction()");
196 CSharp.AppendLine(
"\t\t{");
197 CSharp.AppendLine(
"\t\t\treturn this.CallLambda;");
198 CSharp.AppendLine(
"\t\t}");
200 CSharp.Append(
"\t\tprivate ");
202 if (ReturnType == typeof(
void))
203 CSharp.Append(
"void");
207 CSharp.Append(
"async ");
209 AppendType(ReturnType, CSharp);
213 if (ReturnType.IsConstructedGenericType)
214 ReturnType = ReturnType.GenericTypeArguments[0];
216 ReturnType = typeof(
void);
220 CSharp.Append(
" CallLambda(");
224 foreach (ParameterInfo Parameter
in Parameters)
231 AppendType(Parameter.ParameterType, CSharp);
233 CSharp.Append(Parameter.Name);
236 CSharp.AppendLine(
")");
237 CSharp.AppendLine(
"\t\t{");
239 CSharp.Append(
"\t\t\t");
241 if (ReturnType != typeof(
void))
242 CSharp.Append(
"IElement Result = ");
245 CSharp.Append(
"await this.Lambda.EvaluateAsync(");
247 CSharp.Append(
"this.Lambda.Evaluate(");
249 if (Parameters.Length == 0)
250 CSharp.Append(
"new IElement[0]");
253 CSharp.AppendLine(
"new IElement[]");
254 CSharp.AppendLine(
"\t\t\t{");
258 foreach (ParameterInfo Parameter
in Parameters)
263 CSharp.AppendLine(
",");
265 CSharp.Append(
"\t\t\t\tExpression.Encapsulate(");
266 CSharp.Append(Parameter.Name);
271 CSharp.Append(
"\t\t\t}");
274 CSharp.AppendLine(
", this.Variables);");
277 if (ReturnType != typeof(
void))
280 CSharp.AppendLine(
"\t\t\treturn Result;");
283 CSharp.Append(
"\t\t\treturn (");
284 AppendType(ReturnType, CSharp);
285 CSharp.AppendLine(
")Result.AssociatedObjectValue;");
289 CSharp.AppendLine(
"\t\t}");
290 CSharp.AppendLine(
"\t}");
291 CSharp.AppendLine(
"}");
293 string CSharpCode = CSharp.ToString();
299 s = Path.Combine(Path.GetDirectoryName(GetLocation(typeof(
object))),
"netstandard.dll");
302 Dependencies[s] =
true;
304 while (!(Loop is
null))
306 LoopInfo = Loop.GetTypeInfo();
307 Dependencies[GetLocation(Loop)] =
true;
309 foreach (Type Interface
in LoopInfo.ImplementedInterfaces)
311 s = GetLocation(Interface);
312 Dependencies[s] =
true;
315 foreach (MemberInfo MI2
in LoopInfo.DeclaredMembers)
317 FI = MI2 as FieldInfo;
318 if (!(FI is
null) && !((s = GetLocation(FI.FieldType)).EndsWith(
"mscorlib.dll") || s.EndsWith(
"System.Runtime.dll") || s.EndsWith(
"System.Private.CoreLib.dll")))
319 Dependencies[s] =
true;
320 PI = MI2 as PropertyInfo;
321 if (!(PI is
null) && !((s = GetLocation(PI.PropertyType)).EndsWith(
"mscorlib.dll") || s.EndsWith(
"System.Runtime.dll") || s.EndsWith(
"System.Private.CoreLib.dll")))
322 Dependencies[s] =
true;
324 Loop = LoopInfo.BaseType;
325 if (Loop == typeof(
object))
329 List<Microsoft.CodeAnalysis.MetadataReference> References =
new List<Microsoft.CodeAnalysis.MetadataReference>();
331 foreach (
string Location
in Dependencies.Keys)
333 if (!
string.IsNullOrEmpty(Location))
334 References.Add(Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(Location));
338 AppendType(Type, sb);
340 Microsoft.CodeAnalysis.CSharp.CSharpCompilation Compilation =
341 Microsoft.CodeAnalysis.CSharp.CSharpCompilation.Create(sb.ToString(),
342 new Microsoft.CodeAnalysis.SyntaxTree[] { Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(CSharpCode) },
343 References,
new Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions(
344 Microsoft.CodeAnalysis.OutputKind.DynamicallyLinkedLibrary));
346 MemoryStream Output =
new MemoryStream();
347 MemoryStream PdbOutput =
new MemoryStream();
349 EmitResult CompilerResults = Compilation.Emit(Output, pdbStream: PdbOutput);
351 if (!CompilerResults.Success)
355 sb.Append(
"Unable to create a script proxy for callback methods of type ");
356 AppendType(Type, sb);
357 sb.AppendLine(
". When generating proxy class, the following compiler errors were reported:");
359 foreach (Microsoft.CodeAnalysis.Diagnostic Error in CompilerResults.Diagnostics)
362 sb.Append(Error.Location.ToString());
364 sb.Append(Error.GetMessage());
369 sb.AppendLine(
"Code generated:");
371 sb.AppendLine(CSharpCode);
377 PdbOutput.Position = 0;
380 A = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(Output, PdbOutput);
383 sb.Append(Type.Namespace);
384 sb.Append(
".ScriptCallbacks.ScriptProxy");
385 sb.Append(ClassTypeName);
387 ScriptProxyType = A.GetType(sb.ToString());
388 scriptProxyTypes[Type] = ScriptProxyType;
397 private static readonly TypeInfo delegateTypeInfo = typeof(Delegate).GetTypeInfo();
398 private static readonly TypeInfo taskTypeInfo = typeof(Task).GetTypeInfo();
399 private static readonly Dictionary<Type, Type> scriptProxyTypes =
new Dictionary<Type, Type>();
401 private static string GetLocation(Type T)
403 TypeInfo TI = T.GetTypeInfo();
404 string s = TI.Assembly.Location;
406 if (!
string.IsNullOrEmpty(s))
409 return Path.Combine(Path.GetDirectoryName(GetLocation(typeof(
Expression))), TI.Module.ScopeName);
412 private static void AppendType(Type T, StringBuilder sb)
414 if (T.IsConstructedGenericType)
416 Type T2 = T.GetGenericTypeDefinition();
417 string s = T2.FullName;
418 int i = s.IndexOf(
'`');
421 s = s.Substring(0, i);
428 foreach (Type Arg
in T.GenericTypeArguments)
440 else if (T.HasElementType)
444 AppendType(T.GetElementType(), sb);
447 else if (T.IsPointer)
449 AppendType(T.GetElementType(), sb);
453 sb.Append(T.FullName);
456 sb.Append(T.FullName);
Static class that dynamically manages types and interfaces available in the runtime environment.
Generates a callback function based on script.
override IElement Evaluate(IElement[] Arguments, Variables Variables)
Evaluates the function.
Callback(ScriptNode DelegateType, ScriptNode Lambda, int Start, int Length, Expression Expression)
Generates a callback function based on script.
override string FunctionName
Name of the function
override string[] DefaultArgumentNames
Default Argument names
Callback(ScriptNode DelegateType, ScriptNode ArgumentType, ScriptNode Lambda, int Start, int Length, Expression Expression)
Generates a callback function based on script.
Script runtime exception.
Class managing a script expression.
Base class for multivariate funcions.
ScriptNode[] Arguments
Function arguments.
static readonly ArgumentType[] argumentTypes2Scalar
Two scalar parameters.
static readonly ArgumentType[] argumentTypes3Scalar
Three scalar parameters.
Base class for all nodes in a parsed script tree.
int Length
Length of expression covered by node.
Expression Expression
Expression of which the node is a part.
int Start
Start position in script expression.
Basic interface for all types of elements.
Abstract base class for script proxies used by callback functions.
object GetCallbackFunctionUntyped()
Untyped callback function.
Base interface for lambda expressions.
ArgumentType
Type of parameter used in a function definition or a lambda definition.