3using System.Reflection;
4using System.Threading.Tasks;
21 private readonly
string name;
23 private readonly
int nrParameters;
51 public string Name => this.name;
83 object Object =
Operand.AssociatedObjectValue;
95 T = Object?.GetType() ?? typeof(
object);
101 Arguments =
new IElement[this.nrParameters];
102 for (i = 0; i < this.nrParameters; i++)
117 return Operand.Encapsulate(Elements,
this);
134 object[] ParameterValues;
137 bool DoExtend =
false;
140 lock (this.synchObject)
142 if (this.lastType != T)
145 this.methodType = MethodType.Method;
147 this.byReference =
null;
151 if (!(this.method is
null) && this.methodType == MethodType.Method)
153 if (this.methodParametersTypes.Length !=
this.nrParameters)
156 this.methodType = MethodType.Method;
158 this.byReference =
null;
162 for (i = 0; i < this.methodParametersTypes.Length; i++)
164 PT = this.methodParametersTypes[i].ParameterType;
166 if (PT.IsByRef && Arguments[i].
TryConvertTo(PT.GetElementType(), out Value))
168 this.methodArgumentExtensions[i] =
false;
169 this.methodArguments[i] = Value;
171 else if (Arguments[i].TryConvertTo(PT, out Value))
173 this.methodArgumentExtensions[i] =
false;
174 this.methodArguments[i] = Value;
178 if (Arguments[i].IsScalar ||
Variables is
null)
181 this.methodArgumentExtensions[i] =
true;
182 this.methodArguments[i] =
null;
187 if (i < this.methodParametersTypes.Length)
190 this.methodType = MethodType.Method;
192 this.byReference =
null;
197 if (this.method is
null)
199 if (this.methods is
null)
200 this.methods = this.GetMethods(T);
203 ParameterValues =
null;
206 foreach (MethodRec Rec
in this.methods)
210 if (Instance is
null)
212 if (!Rec.Method.IsStatic)
217 if (Rec.Method.IsStatic)
221 if (Rec.MethodType == MethodType.Method)
223 for (i = 0; i < this.nrParameters; i++)
225 PT = Rec.Parameters[i].ParameterType;
231 if (ParameterValues is
null)
233 Extend =
new bool[this.nrParameters];
234 ParameterValues =
new object[this.nrParameters];
238 ParameterValues[i] = Value;
244 ByRef.
Add(
new KeyValuePair<string, int>(Ref.VariableName, i));
246 ByRef.Add(
new KeyValuePair<string, int>(
null, i));
250 if (ParameterValues is
null)
252 Extend =
new bool[this.nrParameters];
253 ParameterValues =
new object[this.nrParameters];
257 ParameterValues[i] = Value;
266 Extend =
new bool[this.nrParameters];
267 ParameterValues =
new object[this.nrParameters];
271 ParameterValues[i] =
null;
276 if (i < this.nrParameters)
283 this.method = Rec.Method;
284 this.methodType = Rec.MethodType;
285 this.methodParametersTypes = Rec.Parameters;
286 this.methodArguments = ParameterValues;
287 this.methodArgumentExtensions = Extend;
289 if (!(ByRef is
null) && ByRef.Count > 0)
290 this.byReference = ByRef.ToArray();
292 this.byReference =
null;
297 if (this.method is
null)
304 if (!(this.byReference is
null))
305 throw new ScriptException(
"Canonical extensions of method calls having reference type arguments not supported.");
307 return await this.EvaluateCanonicalAsync(Instance, this.method, this.methodType, this.methodParametersTypes,
308 Arguments, this.methodArguments, this.methodArgumentExtensions,
Variables);
312 Value = await this.
EvaluateAsync(Instance, this.method, this.methodType, Arguments, this.methodArguments,
Variables);
317 private async Task<IElement>
EvaluateAsync(
object Instance, MethodInfo Method, MethodType MethodType,
324 case MethodType.Method:
326 Value = Method.Invoke(Instance, ArgumentValues);
329 if (!(this.byReference is
null))
331 int i, j, c = this.byReference.Length;
334 for (i = 0; i < c; i++)
336 j = this.byReference[i].Value;
337 if (
string.IsNullOrEmpty(s = this.byReference[i].Key))
346 case MethodType.LambdaProperty:
353 Value = await LambdaExpression.EvaluateAsync(Arguments,
Variables);
356 case MethodType.LambdaIndexProperty:
359 if (this.methodParametersTypes[0].ParameterType == typeof(
string))
360 Index =
new object[] { this.name };
362 Index =
new object[] {
Expression.
ConvertTo(this.name, this.methodParametersTypes[0].ParameterType,
this) };
364 Value = Method.Invoke(Instance, Index);
369 if (LambdaExpression is
null)
372 Value = await LambdaExpression.EvaluateAsync(Arguments,
Variables);
379 private async Task<IElement> EvaluateCanonicalAsync(
object Object, MethodInfo Method, MethodType MethodType,
382 IEnumerator<IElement>[] Enumerators =
null;
383 ICollection<IElement> Children;
384 IEnumerator<IElement> e;
388 for (i = 0; i < this.nrParameters; i++)
392 if (Arguments[i].IsScalar)
394 if (!Arguments[i].TryConvertTo(ParametersTypes[i].ParameterType, out ArgumentValues[i]))
402 Enumerators =
new IEnumerator<IElement>[this.nrParameters];
403 First = Arguments[i];
406 else if (c != Children.Count)
409 Enumerators[i] = Children.GetEnumerator();
416 object Value = await this.
EvaluateAsync(Object, Method, MethodType, Arguments, ArgumentValues,
Variables);
421 Arguments = (
IElement[])Arguments.Clone();
425 for (i = 0; i < this.nrParameters; i++)
430 if (!(e = Enumerators[i]).MoveNext())
433 Arguments[i] = e.Current;
436 if (i < this.nrParameters)
439 Elements.
Add(await this.EvaluateCanonicalAsync(Object, Method, MethodType, ParametersTypes, Arguments,
443 for (i = 0; i < this.nrParameters; i++)
446 Enumerators[i].Dispose();
452 private MethodRec[] GetMethods(Type Type)
455 ParameterInfo[] ParameterInfo;
456 IEnumerable<MethodInfo> Methods = Type.GetRuntimeMethods();
458 foreach (MethodInfo MI
in Methods)
460 if (MI.IsAbstract || !MI.IsPublic || MI.Name !=
this.name)
463 ParameterInfo = MI.GetParameters();
464 if (ParameterInfo.Length !=
this.nrParameters)
467 Result.
Add(
new MethodRec()
471 MethodType = MethodType.Method
475 if (Result.
Count == 0)
477 PropertyInfo PI = Type.GetRuntimeProperty(this.name);
478 if (!(PI is
null) && PI.GetIndexParameters().Length == 0)
482 else if (!PI.GetMethod.IsPublic)
486 Result.
Add(
new MethodRec()
488 Method = PI.GetMethod,
490 MethodType = MethodType.LambdaProperty
496 Result.
Add(
new MethodRec()
498 Method = PI.GetMethod,
500 MethodType = MethodType.LambdaIndexProperty
508 private enum MethodType
515 private class MethodRec
517 public MethodInfo Method;
518 public ParameterInfo[] Parameters;
519 public MethodType MethodType;
522 private Type lastType =
null;
523 private MethodInfo method =
null;
524 private MethodType methodType = MethodType.Method;
525 private ParameterInfo[] methodParametersTypes =
null;
526 private MethodRec[] methods =
null;
527 private KeyValuePair<string, int>[] byReference =
null;
528 private object[] methodArguments =
null;
529 private bool[] methodArgumentExtensions =
null;
530 private readonly
object synchObject =
new object();
545 if (!this.parameters.ForAllChildNodes(Callback, State, Order))
551 for (i = 0; i < this.nrParameters; i++)
553 Node = this.parameters[i];
556 bool b = !Callback(Node, out
ScriptNode NewNode, State);
557 if (!(NewNode is
null))
559 this.parameters[i] = Node = NewNode;
570 if (!this.parameters.ForAllChildNodes(Callback, State, Order))
581 this.name == O.name &&
582 AreEqual(this.parameters, O.parameters) &&
589 int Result = base.GetHashCode();
591 Result ^= Result << 5 ^
GetHashCode(this.parameters);
A chunked list is a linked list of chunks of objects of type T .
int Count
Number of elements in collection.
void Add(T Item)
Adds an item to the collection.
T[] ToArray()
Returns an array containing all elements of the collection.
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.
static object ConvertTo(IElement Value, Type DesiredType, ScriptNode Node)
Tries to conevert an element value to a desired type.
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 or created.
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(ChunkedList< 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