public object reduce(ScriptScopeContext scope, object target, object expression, object scopeOptions) { var items = target.AssertEnumerable(nameof(reduce)); Type itemType = null; if (!(expression is JsArrowFunctionExpression arrowExpr)) { throw new NotSupportedException($"{nameof(reduce)} expects an arrow expression but was instead '{expression.GetType().Name}'"); } if (arrowExpr.Params.Length != 2) { throw new NotSupportedException($"{nameof(reduce)} expects 2 params but was instead {arrowExpr.Params.Length}"); } var accumulatorBinding = arrowExpr.Params[0].Name; var itemBinding = arrowExpr.Params[1].Name; var expr = arrowExpr.Body; var scopedParams = scopeOptions as Dictionary <string, object> ?? new Dictionary <string, object>(); var accumulator = scopedParams.TryGetValue("initialValue", out object initialValue) ? initialValue.ConvertTo <double>() : !(scopeOptions is IDictionary) ? scopeOptions.ConvertTo <double>() : 0; var i = 0; scope = scope.Clone(); foreach (var item in items) { if (item == null) { continue; } scope.AddItemToScope(accumulatorBinding, accumulator); scope.AddItemToScope("index", i++); scope.AddItemToScope(itemBinding, item); var result = expr.Evaluate(scope); if (result == null) { continue; } if (itemType == null) { itemType = result.GetType(); } accumulator = result.ConvertTo <double>(); } return(itemType == null || itemType == typeof(double) ? accumulator : accumulator.ConvertTo(itemType)); }
public IgnoreResult forEach(ScriptScopeContext scope, object target, JsArrowFunctionExpression arrowExpr) { var token = arrowExpr.Body; scope = scope.Clone(); if (target is IList list) { var itemBinding = arrowExpr.Params[0].Name; var indexBinding = arrowExpr.Params.Length > 1 ? arrowExpr.Params[1].Name : ScriptConstants.Index; var arrayBinding = arrowExpr.Params.Length > 2 ? arrowExpr.Params[2].Name : null; for (var i = 0; i < list.Count; i++) { scope.ScopedParams[indexBinding] = i; if (arrayBinding != null) { scope.ScopedParams[arrayBinding] = list; } scope = scope.AddItemToScope(itemBinding, list[i]); token.Evaluate(scope); } } else if (target is IDictionary d) { if (arrowExpr.Params.Length != 2) { throw new NotSupportedException("Dictionary.forEach requires 2 lambda params"); } var keyBinding = arrowExpr.Params[0].Name; var valueBinding = arrowExpr.Params[1].Name; foreach (var key in d.Keys) { scope.ScopedParams[keyBinding] = key; scope.ScopedParams[valueBinding] = d[key]; token.Evaluate(scope); } } else { throw new NotSupportedException("Can only use forEach on Lists or Dictionaries"); } return(IgnoreResult.Value); }
private object applyInternal(string filterName, ScriptScopeContext scope, object target, object expression, object scopeOptions, Func <double, double, double> fn) { if (target is double d) { return(fn(d, expression.ConvertTo <double>())); } if (target is int i) { return((int)fn(i, expression.ConvertTo <double>())); } if (target is long l) { return((long)fn(l, expression.ConvertTo <double>())); } var items = target.AssertEnumerable(filterName); var total = filterName == nameof(min) ? double.MaxValue : 0; Type itemType = null; if (expression != null) { scope = scope.Clone(); var expr = scope.AssertExpression(filterName, expression, scopeOptions, out var itemBinding); foreach (var item in items) { if (item == null) { continue; } scope.AddItemToScope(itemBinding, item); var result = expr.Evaluate(scope); if (result == null) { continue; } if (itemType == null) { itemType = result.GetType(); } total = fn(total, result.ConvertTo <double>()); } } else { foreach (var item in items) { if (item == null) { continue; } if (itemType == null) { itemType = item.GetType(); } total = fn(total, item.ConvertTo <double>()); } } if (filterName == nameof(min) && itemType == null) { return(0); } if (expression == null && itemType == null) { itemType = target.GetType().FirstGenericType()?.GetGenericArguments().FirstOrDefault(); } return(itemType == null || itemType == typeof(double) ? total : total.ConvertTo(itemType)); }