2using System.Reflection;
3using System.Collections.Generic;
8using System.Threading.Tasks;
19 private readonly
string name;
21 private readonly
int nrParameters;
49 public string Name => this.name;
81 object Object =
Operand.AssociatedObjectValue;
93 T = Object?.GetType() ?? typeof(
object);
99 Arguments =
new IElement[this.nrParameters];
100 for (i = 0; i < this.nrParameters; i++)
110 LinkedList<IElement> Elements =
new LinkedList<IElement>();
115 return Operand.Encapsulate(Elements,
this);
132 object[] ParameterValues;
135 bool DoExtend =
false;
138 lock (this.synchObject)
140 if (this.lastType != T)
143 this.methodType = MethodType.Method;
145 this.byReference =
null;
149 if (!(this.method is
null) && this.methodType == MethodType.Method)
151 if (this.methodParametersTypes.Length !=
this.nrParameters)
154 this.methodType = MethodType.Method;
156 this.byReference =
null;
160 for (i = 0; i < this.methodParametersTypes.Length; i++)
162 PT = this.methodParametersTypes[i].ParameterType;
164 if (PT.IsByRef && Arguments[i].
TryConvertTo(PT.GetElementType(), out Value))
166 this.methodArgumentExtensions[i] =
false;
167 this.methodArguments[i] = Value;
169 else if (Arguments[i].TryConvertTo(PT, out Value))
171 this.methodArgumentExtensions[i] =
false;
172 this.methodArguments[i] = Value;
176 if (Arguments[i].IsScalar ||
Variables is
null)
179 this.methodArgumentExtensions[i] =
true;
180 this.methodArguments[i] =
null;
185 if (i < this.methodParametersTypes.Length)
188 this.methodType = MethodType.Method;
190 this.byReference =
null;
195 if (this.method is
null)
197 if (this.methods is
null)
198 this.methods = this.GetMethods(T);
200 List<KeyValuePair<string, int>> ByRef =
null;
201 ParameterValues =
null;
204 foreach (MethodRec Rec
in this.methods)
208 if (Instance is
null)
210 if (!Rec.Method.IsStatic)
215 if (Rec.Method.IsStatic)
219 if (Rec.MethodType == MethodType.Method)
221 for (i = 0; i < this.nrParameters; i++)
223 PT = Rec.Parameters[i].ParameterType;
229 if (ParameterValues is
null)
231 Extend =
new bool[this.nrParameters];
232 ParameterValues =
new object[this.nrParameters];
236 ParameterValues[i] = Value;
239 ByRef =
new List<KeyValuePair<string, int>>();
242 ByRef.Add(
new KeyValuePair<string, int>(Ref.VariableName, i));
244 ByRef.Add(
new KeyValuePair<string, int>(
null, i));
248 if (ParameterValues is
null)
250 Extend =
new bool[this.nrParameters];
251 ParameterValues =
new object[this.nrParameters];
255 ParameterValues[i] = Value;
264 Extend =
new bool[this.nrParameters];
265 ParameterValues =
new object[this.nrParameters];
269 ParameterValues[i] =
null;
274 if (i < this.nrParameters)
281 this.method = Rec.Method;
282 this.methodType = Rec.MethodType;
283 this.methodParametersTypes = Rec.Parameters;
284 this.methodArguments = ParameterValues;
285 this.methodArgumentExtensions = Extend;
287 if (!(ByRef is
null) && ByRef.Count > 0)
288 this.byReference = ByRef.ToArray();
290 this.byReference =
null;
295 if (this.method is
null)
302 if (!(this.byReference is
null))
303 throw new ScriptException(
"Canonical extensions of method calls having reference type arguments not supported.");
305 return await this.EvaluateCanonicalAsync(Instance, this.method, this.methodType, this.methodParametersTypes,
306 Arguments, this.methodArguments, this.methodArgumentExtensions,
Variables);
310 Value = await this.
EvaluateAsync(Instance, this.method, this.methodType, Arguments, this.methodArguments,
Variables);
315 private async Task<IElement>
EvaluateAsync(
object Instance, MethodInfo Method, MethodType MethodType,
322 case MethodType.Method:
324 Value = Method.Invoke(Instance, ArgumentValues);
327 if (!(this.byReference is
null))
329 int i, j, c = this.byReference.Length;
332 for (i = 0; i < c; i++)
334 j = this.byReference[i].Value;
335 if (
string.IsNullOrEmpty(s = this.byReference[i].Key))
344 case MethodType.LambdaProperty:
351 Value = await LambdaExpression.EvaluateAsync(Arguments,
Variables);
354 case MethodType.LambdaIndexProperty:
355 Value = Method.Invoke(Instance,
new object[] { this.name });
359 if (LambdaExpression is
null)
362 Value = await LambdaExpression.EvaluateAsync(Arguments,
Variables);
369 private async Task<IElement> EvaluateCanonicalAsync(
object Object, MethodInfo Method, MethodType MethodType,
372 IEnumerator<IElement>[] Enumerators =
null;
373 ICollection<IElement> Children;
374 IEnumerator<IElement> e;
378 for (i = 0; i < this.nrParameters; i++)
382 if (Arguments[i].IsScalar)
384 if (!Arguments[i].TryConvertTo(ParametersTypes[i].ParameterType, out ArgumentValues[i]))
392 Enumerators =
new IEnumerator<IElement>[this.nrParameters];
393 First = Arguments[i];
396 else if (c != Children.Count)
399 Enumerators[i] = Children.GetEnumerator();
406 object Value = await this.
EvaluateAsync(Object, Method, MethodType, Arguments, ArgumentValues,
Variables);
410 LinkedList<IElement> Elements =
new LinkedList<IElement>();
411 Arguments = (
IElement[])Arguments.Clone();
415 for (i = 0; i < this.nrParameters; i++)
420 if (!(e = Enumerators[i]).MoveNext())
423 Arguments[i] = e.Current;
426 if (i < this.nrParameters)
429 Elements.AddLast(await this.EvaluateCanonicalAsync(Object, Method, MethodType, ParametersTypes, Arguments,
433 for (i = 0; i < this.nrParameters; i++)
436 Enumerators[i].Dispose();
442 private MethodRec[] GetMethods(Type Type)
444 List<MethodRec> Result =
new List<MethodRec>();
445 ParameterInfo[] ParameterInfo;
446 IEnumerable<MethodInfo> Methods = Type.GetRuntimeMethods();
448 foreach (MethodInfo MI
in Methods)
450 if (MI.IsAbstract || !MI.IsPublic || MI.Name !=
this.name)
453 ParameterInfo = MI.GetParameters();
454 if (ParameterInfo.Length !=
this.nrParameters)
457 Result.Add(
new MethodRec()
461 MethodType = MethodType.Method
465 if (Result.Count == 0)
467 PropertyInfo PI = Type.GetRuntimeProperty(this.name);
468 if (!(PI is
null) && PI.GetIndexParameters().Length == 0)
472 else if (!PI.GetMethod.IsPublic)
476 Result.Add(
new MethodRec()
478 Method = PI.GetMethod,
480 MethodType = MethodType.LambdaProperty
486 Result.Add(
new MethodRec()
488 Method = PI.GetMethod,
490 MethodType = MethodType.LambdaIndexProperty
495 return Result.ToArray();
498 private enum MethodType
505 private class MethodRec
507 public MethodInfo Method;
508 public ParameterInfo[] Parameters;
509 public MethodType MethodType;
512 private Type lastType =
null;
513 private MethodInfo method =
null;
514 private MethodType methodType = MethodType.Method;
515 private ParameterInfo[] methodParametersTypes =
null;
516 private MethodRec[] methods =
null;
517 private KeyValuePair<string, int>[] byReference =
null;
518 private object[] methodArguments =
null;
519 private bool[] methodArgumentExtensions =
null;
520 private readonly
object synchObject =
new object();
535 if (!this.parameters.ForAllChildNodes(Callback, State, Order))
541 for (i = 0; i < this.nrParameters; i++)
543 Node = this.parameters[i];
546 bool b = !Callback(Node, out
ScriptNode NewNode, State);
547 if (!(NewNode is
null))
549 this.parameters[i] = Node = NewNode;
560 if (!this.parameters.ForAllChildNodes(Callback, State, Order))
571 this.name == O.name &&
572 AreEqual(this.parameters, O.parameters) &&
579 int Result = base.GetHashCode();
581 Result ^= Result << 5 ^
GetHashCode(this.parameters);
Static class that dynamically manages types and interfaces available in the runtime environment.
static object[] NoParameters
Contains an empty array of parameter values.
Base class for script exceptions.
Script runtime exception.
Class managing a script expression.
static IElement Encapsulate(object Value)
Encapsulates an object.
Base class for all unary operators performing operand null checks.
bool NullCheck
If null check is to be used.
readonly bool nullCheck
If null should be returned if operand is null.
Base class for all nodes in a parsed script tree.
bool ForAllChildNodes(ScriptNodeEventHandler Callback, object State, bool DepthFirst)
Calls the callback method for all child nodes.
int Length
Length of expression covered by node.
static bool AreEqual(ScriptNode S1, ScriptNode S2)
Compares if two script nodes are equal.
static async Task< object > WaitPossibleTask(object Result)
Waits for any asynchronous process to terminate.
int Start
Start position in script expression.
void SetParent(ScriptNode Parent)
Sets the parent node. Can only be used when expression is being parsed.
ScriptNode Operand
Operand.
Represents a variable reference.
static readonly ObjectValue Null
Null value.
Named method call operator.
override bool Equals(object obj)
override int GetHashCode()
override bool ForAllChildNodes(ScriptNodeEventHandler Callback, object State, SearchMethod Order)
Calls the callback method for all child nodes.
override bool IsAsynchronous
If the node (or its decendants) include asynchronous evaluation. Asynchronous nodes should be evaluat...
override async Task< IElement > EvaluateAsync(IElement Operand, Variables Variables)
Evaluates the node, using the variables provided in the Variables collection.
ScriptNode[] Parameters
Method arguments.
override IElement Evaluate(IElement Operand, Variables Variables)
Evaluates the node, using the variables provided in the Variables collection.
async Task< IElement > EvaluateAsync(Type T, object Instance, IElement[] Arguments, Variables Variables)
Executes a code-behind method.
NamedMethodCall(ScriptNode Operand, string Name, ScriptNode[] Parameters, bool NullCheck, int Start, int Length, Expression Expression)
Named method call operator.
static bool TryGetIndexProperty(Type T, bool ForReading, bool ForWriting, out PropertyInfo PropertyInfo, out ParameterInfo[] Parameters)
Tries to get a one-dimensional index property of a Type.
Basic interface for all types of elements.
bool TryConvertTo(Type DesiredType, out object Value)
Converts the value to a .NET type.
object AssociatedObjectValue
Associated object value.
ICollection< IElement > ChildElements
An enumeration of child elements. If the element is a scalar, this property will return null.
IElement Encapsulate(ICollection< IElement > Elements, ScriptNode Node)
Encapsulates a set of elements into a similar structure as that provided by the current element.
bool IsScalar
If the element represents a scalar value.
Base interface for lambda expressions.
delegate bool ScriptNodeEventHandler(ScriptNode Node, out ScriptNode NewNode, object State)
Delegate for ScriptNode callback methods.
SearchMethod
Method to traverse the expression structure