Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
BinaryOperator.cs
1using System;
7
8namespace Waher.Script.Model
9{
13 public abstract class BinaryOperator : ScriptNode
14 {
18 protected ScriptNode left;
19
23 protected ScriptNode right;
24
28 protected bool isAsync;
29
39 : base(Start, Length, Expression)
40 {
41 this.left = Left;
42 this.left?.SetParent(this);
43
44 this.right = Right;
45 this.right?.SetParent(this);
46
47 this.CalcIsAsync();
48 }
49
53 protected virtual void CalcIsAsync()
54 {
55 this.isAsync =
56 (this.left?.IsAsynchronous ?? false) ||
57 (this.right?.IsAsynchronous ?? false);
58 }
59
63 public ScriptNode LeftOperand => this.left;
64
69
73 public virtual string DefaultVariableName
74 {
75 get
76 {
77 if (this.left is IDifferentiable Left &&
78 this.right is IDifferentiable Right)
79 {
80 string s = Left.DefaultVariableName;
81 if (s is null)
82 return null;
83 else if (s == Right.DefaultVariableName)
84 return s;
85 else
86 return null;
87 }
88 else
89 return null;
90 }
91 }
92
97 public override bool IsAsynchronous => this.isAsync;
98
106 public override bool ForAllChildNodes(ScriptNodeEventHandler Callback, object State, SearchMethod Order)
107 {
108 if (Order == SearchMethod.DepthFirst)
109 {
110 if (!(this.left?.ForAllChildNodes(Callback, State, Order) ?? true))
111 return false;
112
113 if (!(this.right?.ForAllChildNodes(Callback, State, Order) ?? true))
114 return false;
115 }
116
117 ScriptNode NewNode;
118 bool RecalcIsAsync = false;
119 bool b;
120
121 if (!(this.left is null))
122 {
123 b = !Callback(this.left, out NewNode, State);
124 if (!(NewNode is null))
125 {
126 this.left = NewNode;
127 this.left.SetParent(this);
128
129 RecalcIsAsync = true;
130 }
131
132 if (b || (Order == SearchMethod.TreeOrder && !this.left.ForAllChildNodes(Callback, State, Order)))
133 {
134 if (RecalcIsAsync)
135 this.CalcIsAsync();
136
137 return false;
138 }
139 }
140
141 if (!(this.right is null))
142 {
143 b = !Callback(this.right, out NewNode, State);
144 if (!(NewNode is null))
145 {
146 this.right = NewNode;
147 this.right.SetParent(this);
148
149 RecalcIsAsync = true;
150 }
151
152 if (b || (Order == SearchMethod.TreeOrder && !this.right.ForAllChildNodes(Callback, State, Order)))
153 {
154 if (RecalcIsAsync)
155 this.CalcIsAsync();
156
157 return false;
158 }
159 }
160
161 if (RecalcIsAsync)
162 this.CalcIsAsync();
163
164 if (Order == SearchMethod.BreadthFirst)
165 {
166 if (!(this.left?.ForAllChildNodes(Callback, State, Order) ?? true))
167 return false;
168
169 if (!(this.right?.ForAllChildNodes(Callback, State, Order) ?? true))
170 return false;
171 }
172
173 return true;
174 }
175
177 public override bool Equals(object obj)
178 {
179 return obj is BinaryOperator O &&
180 AreEqual(this.left, O.left) &&
181 AreEqual(this.right, O.right) &&
182 base.Equals(obj);
183 }
184
186 public override int GetHashCode()
187 {
188 int Result = base.GetHashCode();
189 Result ^= Result << 5 ^ GetHashCode(this.left);
190 Result ^= Result << 5 ^ GetHashCode(this.right);
191 return Result;
192 }
193
204 public static IElement EvaluateNamedOperator(string Name, IElement Left, IElement Right, ScriptNode Node)
205 {
206 Type LeftType = Left.AssociatedObjectValue?.GetType() ?? typeof(object);
207 Type RightType = Right.AssociatedObjectValue?.GetType() ?? typeof(object);
208 IBinaryOperator CustomOperator = null;
209 bool Found;
210
211 lock (customBinaryOperators)
212 {
213 Found =
214 customBinaryOperators.TryGetValue(Name, out Dictionary<Type, Dictionary<Type, IBinaryOperator>> ByLeftType) &&
215 ByLeftType.TryGetValue(LeftType, out Dictionary<Type, IBinaryOperator> ByRightType) &&
216 ByRightType.TryGetValue(RightType, out CustomOperator);
217 }
218
219 if (!(CustomOperator is null))
220 return CustomOperator.Evaluate(new BinaryOperation(Name, Left, Right), Node);
221
222 ScriptNode[] ArgumentNodes = new ScriptNode[2];
223 NamedMethodCall OperatorMethod = new NamedMethodCall(null, Name, ArgumentNodes,
224 false, Node?.Start ?? 0, Node?.Length ?? 0, Node?.Expression);
225
226 IElement[] Arguments = new IElement[] { Left, Right };
227 IElement Result = OperatorMethod.EvaluateAsync(LeftType, null, Arguments, null).Result;
228
229 if (!(Result is null))
230 return Result;
231
232 Result = OperatorMethod.EvaluateAsync(RightType, null, Arguments, null).Result;
233
234 if (!(Result is null))
235 return Result;
236
237 if (!Found)
238 {
239 BinaryOperation BinaryOperation = new BinaryOperation(Name, Left, Right);
240
241 CustomOperator = Types.FindBest<IBinaryOperator, IBinaryOperation>(BinaryOperation);
242
243 lock (customBinaryOperators)
244 {
245 if (!customBinaryOperators.TryGetValue(Name, out Dictionary<Type, Dictionary<Type, IBinaryOperator>> ByLeftType))
246 {
247 ByLeftType = new Dictionary<Type, Dictionary<Type, IBinaryOperator>>();
248 customBinaryOperators[Name] = ByLeftType;
249 }
250
251 if (!ByLeftType.TryGetValue(LeftType, out Dictionary<Type, IBinaryOperator> ByRightType))
252 {
253 ByRightType = new Dictionary<Type, IBinaryOperator>();
254 ByLeftType[LeftType] = ByRightType;
255 }
256
257 ByRightType[RightType] = CustomOperator;
258 }
259
260 if (!(CustomOperator is null))
261 return CustomOperator.Evaluate(BinaryOperation, Node);
262 }
263
264 return null;
265 }
266
267 private static readonly Dictionary<string, Dictionary<Type, Dictionary<Type, IBinaryOperator>>>
268 customBinaryOperators = new Dictionary<string, Dictionary<Type, Dictionary<Type, IBinaryOperator>>>();
269 }
270}
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
Class managing a script expression.
Definition: Expression.cs:41
Information about a binary operation for use with custom binary operators.
Base class for all binary operators.
ScriptNode RightOperand
Right operand.
virtual void CalcIsAsync()
Recalculates if operator is asynchronous or not.
ScriptNode LeftOperand
Left operand.
override bool IsAsynchronous
If the node (or its decendants) include asynchronous evaluation. Asynchronous nodes should be evaluat...
ScriptNode right
Right operand.
ScriptNode left
Left operand.
override bool ForAllChildNodes(ScriptNodeEventHandler Callback, object State, SearchMethod Order)
Calls the callback method for all child nodes.
override bool Equals(object obj)
static IElement EvaluateNamedOperator(string Name, IElement Left, IElement Right, ScriptNode Node)
Evaluates a named operator available in code-behind.
BinaryOperator(ScriptNode Left, ScriptNode Right, int Start, int Length, Expression Expression)
Base class for all binary operators.
bool isAsync
If subtree is asynchroneous.
virtual string DefaultVariableName
Default variable name, if any, null otherwise.
Base class for all nodes in a parsed script tree.
Definition: ScriptNode.cs:69
int Length
Length of expression covered by node.
Definition: ScriptNode.cs:101
static bool AreEqual(ScriptNode S1, ScriptNode S2)
Compares if two script nodes are equal.
Definition: ScriptNode.cs:275
int Start
Start position in script expression.
Definition: ScriptNode.cs:92
virtual bool IsAsynchronous
If the node (or its decendants) include asynchronous evaluation. Asynchronous nodes should be evaluat...
Definition: ScriptNode.cs:142
void SetParent(ScriptNode Parent)
Sets the parent node. Can only be used when expression is being parsed or created.
Definition: ScriptNode.cs:132
override async Task< IElement > EvaluateAsync(IElement Operand, Variables Variables)
Evaluates the node, using the variables provided in the Variables collection.
IElement Evaluate(IBinaryOperation Operation, ScriptNode Node)
Evaluates the custom binary operator.
Basic interface for all types of elements.
Definition: IElement.cs:21
object AssociatedObjectValue
Associated object value.
Definition: IElement.cs:34
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
Definition: ScriptNode.cs:38