internal SearchExpressionContext(SearchExpressionRuntime runtime, SearchExpression expression, SearchExpression[] args, SearchExpressionExecutionFlags flags) { this.runtime = runtime; this.expression = expression; this.flags = flags; this.args = args; }
public SearchExpressionRuntime(SearchContext searchContext, SearchExpressionExecutionFlags flags) { search = searchContext; frames = new Stack <SearchExpressionContext>(); state = new ExecutionState(); items = new Stack <SearchItem>(); frames.Push(new SearchExpressionContext(this, null, null, SearchExpressionExecutionFlags.Root | flags)); }
internal IEnumerable <SearchItem> Execute(SearchContext searchContext, SearchExpressionExecutionFlags executionFlags) { var runtime = new SearchExpressionRuntime(searchContext, executionFlags); if (executionFlags.HasFlag(SearchExpressionExecutionFlags.ThreadedEvaluation)) { return(TaskEvaluatorManager.Evaluate(runtime.current, this)); } return(Execute(runtime.current, executionFlags)); }
internal IEnumerable <SearchItem> Execute(SearchExpressionContext c, SearchExpressionExecutionFlags executionFlags) { if (!evaluator.valid || evaluator.execute == null) { c.ThrowError("Invalid expression evaluator"); } try { if (!evaluator.hints.HasFlag(SearchExpressionEvaluationHints.ThreadNotSupported)) { return(Evaluate(c, executionFlags)); } // We cannot only return the IEnumerable of the evaluator, as the iteration itself needs to be // done on the main thread. If we return the IEnumerable itself, we will unroll the items and call the evaluator // in the evaluation thread. return(TaskEvaluatorManager.EvaluateMainThreadUnroll(() => Evaluate(c, executionFlags))); } catch (SearchExpressionEvaluatorException ex) { ExceptionDispatchInfo.Capture(ex).Throw(); return(null); // To stop visual studio complaining about not all code path return a value } }
public bool HasFlag(SearchExpressionExecutionFlags checkFlag) { return(flags.HasFlag(checkFlag)); }
public IDisposable Push(SearchExpression searchExpression, IEnumerable <SearchExpression> args, SearchExpressionExecutionFlags flags) { flags |= frames.Peek().flags & SearchExpressionExecutionFlags.TransferedFlags; frames.Push(new SearchExpressionContext(this, searchExpression, args.ToArray(), flags)); return(new PushPopScope <SearchExpressionContext>(frames)); }
private IEnumerable <SearchItem> Evaluate(SearchExpressionContext c, SearchExpressionExecutionFlags flags) { var args = new List <SearchExpression>(); foreach (var p in parameters) { var evalHints = p.evaluator.hints; if (evalHints.HasFlag(SearchExpressionEvaluationHints.AlwaysExpand) || (p.types.HasFlag(SearchExpressionType.Expandable) && evalHints.HasFlag(SearchExpressionEvaluationHints.ExpandSupported))) { foreach (var exprItem in p.Execute(c, SearchExpressionExecutionFlags.Expand)) { if (exprItem != null) { if (exprItem.data is SearchExpression expr) { args.Add(expr); } else { c.ThrowError($"cannot expand {p}"); } } else { yield return(null); } } } else if (p.types.HasFlag(SearchExpressionType.Expandable)) { foreach (var exprItem in p.Execute(c)) { if (exprItem == null) { yield return(null); continue; } if (exprItem.value != null) { if (Utils.TryGetNumber(exprItem.value, out var d)) { args.Add(new SearchExpression(SearchExpressionType.Number, d.ToString().GetStringView(), Parsers.ConstantEvaluator)); } else if (exprItem.value is string s) { args.Add(new SearchExpression(SearchExpressionType.Text, s.GetStringView(), Parsers.ConstantEvaluator)); } else { c.ThrowError("Cannot expand parameters"); } } else { c.ThrowError("Cannot expand null value"); } } } else { args.Add(p); } } using (c.runtime.Push(this, args, flags)) { var skipNull = c.HasFlag(SearchExpressionExecutionFlags.ThreadedEvaluation) && !c.HasFlag(SearchExpressionExecutionFlags.PassNull); var executeContext = c.runtime.current; var timeoutWatch = new System.Diagnostics.Stopwatch(); timeoutWatch.Start(); foreach (var r in evaluator.execute(executeContext)) { if (r != null) { timeoutWatch.Restart(); yield return(r); } else if (!skipNull) { if (timeoutWatch.Elapsed.TotalSeconds > 3.0d) { c.ThrowError("Timeout"); } yield return(null); } } } }