private static EvaluationResult GroupBy(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg); using (var disposableFrame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { // To avoid warning: access to disposable closure. var frame = disposableFrame; var entry = context.TopStack; var result = receiver.Values.GroupBy(obj => { frame.SetArgument(0, obj); return(context.InvokeClosure(closure, frame)); }); var arr = result.Select(grp => { var grpArrayLit = ArrayLiteral.CreateWithoutCopy(grp.ToArray(), entry.InvocationLocation, entry.Path); var bindings = new List <Binding> { new Binding(StringId.Create(context.FrontEndContext.StringTable, "key"), grp.Key, location: default(LineInfo)), new Binding(StringId.Create(context.FrontEndContext.StringTable, "values"), grpArrayLit, location: default(LineInfo)), }; return(EvaluationResult.Create(ObjectLiteral.Create(bindings, entry.InvocationLocation, entry.Path))); }).ToArray(); return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(arr, entry.InvocationLocation, entry.Path))); } }
private static EvaluationResult Reduce(Context context, ArrayLiteral receiver, EvaluationResult arg0, EvaluationResult arg1, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg0); int paramsCount = closure.Function.Params; var accumulator = arg1; if (receiver.Length > 0) { using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { for (int i = 0; i < receiver.Length; i++) { frame.TrySetArguments(paramsCount, accumulator, receiver[i], i, EvaluationResult.Create(receiver)); accumulator = context.InvokeClosure(closure, frame); if (accumulator.IsErrorValue) { return(EvaluationResult.Error); } } } } return(accumulator); }
private static EvaluationResult Map(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg); int paramsCount = closure.Function.Params; if (receiver.Length == 0) { return(EvaluationResult.Create(receiver)); } var result = new EvaluationResult[receiver.Length]; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { for (int i = 0; i < receiver.Length; ++i) { frame.TrySetArguments(paramsCount, receiver[i], i, EvaluationResult.Create(receiver)); result[i] = context.InvokeClosure(closure, frame); if (result[i].IsErrorValue) { return(EvaluationResult.Error); } } return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(result, context.TopStack.InvocationLocation, context.TopStack.Path))); } }
private static EvaluationResult Find(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg); int paramsCount = closure.Function.Params; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { for (int i = 0; i < receiver.Length; ++i) { frame.TrySetArguments(paramsCount, receiver[i], i, EvaluationResult.Create(receiver)); EvaluationResult lambdaResult = context.InvokeClosure(closure, frame); if (lambdaResult.IsErrorValue) { return(EvaluationResult.Error); } if (Expression.IsTruthy(lambdaResult)) { return(receiver[i]); } } return(EvaluationResult.Undefined); } }
private static EvaluationResult ForEach(Context context, OrderedSet receiver, EvaluationResult arg, EvaluationStackFrame captures) { var cls = Converter.ExpectClosure(arg); var result = new EvaluationResult[receiver.Count]; int paramsCount = cls.Function.Params; using (var frame = EvaluationStackFrame.Create(cls.Function, captures.Frame)) { int i = 0; foreach (var item in receiver) { frame.TrySetArguments(paramsCount, item); result[i] = context.InvokeClosure(cls, frame); if (result[i].IsErrorValue) { return(EvaluationResult.Error); } ++i; } return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(result, context.TopStack.InvocationLocation, context.TopStack.Path))); } }
private static EvaluationResult ForEach(Context context, OrderedMap receiver, EvaluationResult arg, EvaluationStackFrame captures) { var cls = Converter.ExpectClosure(arg); var result = new EvaluationResult[receiver.Count]; int paramsCount = cls.Function.Params; // One frame can be reused for multiple calls of a callback function using (var frame = EvaluationStackFrame.Create(cls.Function, captures.Frame)) { var entry = context.TopStack; int i = 0; foreach (var kvp in receiver) { var kvpAsArray = ArrayLiteral.CreateWithoutCopy(new EvaluationResult[] { kvp.Key, kvp.Value }, entry.InvocationLocation, entry.Path); frame.TrySetArguments(paramsCount, EvaluationResult.Create(kvpAsArray)); result[i] = context.InvokeClosure(cls, frame); if (result[i].IsErrorValue) { return(EvaluationResult.Error); } ++i; } return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(result, entry.InvocationLocation, entry.Path))); } }
private static EvaluationResult MapMany(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg); int paramsCount = closure.Function.Params; if (receiver.Length == 0) { return(EvaluationResult.Create(receiver)); } // WIP: try to pool this var arrays = new ArrayLiteral[receiver.Length]; int count = 0; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { for (int i = 0; i < receiver.Length; ++i) { frame.TrySetArguments(paramsCount, receiver[i], i, EvaluationResult.Create(receiver)); EvaluationResult mapResult = context.InvokeClosure(closure, frame); if (mapResult.IsErrorValue) { return(EvaluationResult.Error); } if (!(mapResult.Value is ArrayLiteral mappedElems)) { throw Converter.CreateException <ArrayLiteral>(mapResult, default(ConversionContext)); } arrays[i] = mappedElems; count += mappedElems.Length; } if (count == 0) { return(EvaluationResult.Create(arrays[0])); } var result = new EvaluationResult[count]; var nextIndex = 0; for (int i = 0; i < arrays.Length; ++i) { var array = arrays[i]; var length = array.Length; if (length > 0) { array.Copy(0, result, nextIndex, length); } nextIndex += length; } return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(result, context.TopStack.InvocationLocation, context.TopStack.Path))); } }
/// <summary> /// Helper method that returns a (object, object) -> object from a closure /// </summary> protected static MergeFunction GetCustomMergeFunctionFromClosure(Context context, EvaluationStackFrame captures, EvaluationResult customMergeClosure) { var closure = Converter.ExpectClosure(customMergeClosure); int paramsCount = closure.Function.Params; return((leftObject, rightObject) => { using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { frame.TrySetArguments(paramsCount, leftObject, rightObject); return context.InvokeClosure(closure, frame); } }); }
private EvaluationResult ExpectFailure(Context context, ModuleLiteral env, EvaluationStackFrame args) { var closure = Args.AsClosure(args, 0); var expectedResults = Args.AsArrayLiteral(args, 1); using (var frame = EvaluationStackFrame.Create(closure.Function, args.Frame)) { var result = context.InvokeClosure(closure, frame); if (!result.IsErrorValue) { Assert.True(false, "Expected the code under test to throw a failure, but none was returned."); } if (!m_getDiagnostics().Any(diagnostic => diagnostic.Level == EventLevel.Error)) { Assert.True(false, "Expected to see at least one reported error, but none encountered."); } for (int i = 0; i < expectedResults.Count; i++) { if (expectedResults[i].Value is string expectedContent) { // String case Assert.False(string.IsNullOrEmpty(expectedContent), "Empty strings are not supported as expected error messages"); ValidateExpectedMessageLogged(null, expectedContent); } else { // Object case var obj = Converter.ExpectObjectLiteral( expectedResults[i], new ConversionContext(pos: i, objectCtx: expectedResults)); var code = Converter.ExtractInt(obj, m_testingExpectedMessageCode); expectedContent = Converter.ExtractString(obj, m_testingExpectedMessageContent); ValidateExpectedMessageLogged(code, expectedContent); } } return(EvaluationResult.Undefined); } }
private static EvaluationResult MapWithState(Context context, ArrayLiteral receiver, EvaluationResult arg0, EvaluationResult arg1, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg0); int paramsCount = closure.Function.Params; var state = arg1; var arrays = new EvaluationResult[receiver.Length]; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { var entry = context.TopStack; var stateName = SymbolAtom.Create(context.FrontEndContext.StringTable, "state"); var elemsName = SymbolAtom.Create(context.FrontEndContext.StringTable, "elems"); var elemName = SymbolAtom.Create(context.FrontEndContext.StringTable, "elem"); for (int i = 0; i < receiver.Length; ++i) { frame.TrySetArguments(paramsCount, state, receiver[i], i, EvaluationResult.Create(receiver)); EvaluationResult mapResult = context.InvokeClosure(closure, frame); if (mapResult.IsErrorValue) { return(EvaluationResult.Error); } if (!(mapResult.Value is ObjectLiteral objectResult)) { throw Converter.CreateException <ObjectLiteral>(mapResult, default(ConversionContext)); } arrays[i] = objectResult[elemName]; state = objectResult[stateName]; } var bindings = new List <Binding> { new Binding(elemsName, ArrayLiteral.CreateWithoutCopy(arrays, entry.InvocationLocation, entry.Path), location: default(LineInfo)), new Binding(stateName, state, location: default(LineInfo)), }; return(EvaluationResult.Create(ObjectLiteral.Create(bindings, entry.InvocationLocation, entry.Path))); } }
private static EvaluationResult SomeOrAll(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures, bool isSome) { var closure = Converter.ExpectClosure(arg); if (receiver.Length == 0) { return(EvaluationResult.Create(!isSome)); } int paramsCount = closure.Function.Params; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { for (int i = 0; i < receiver.Length; ++i) { frame.TrySetArguments(paramsCount, receiver[i], i, EvaluationResult.Create(receiver)); EvaluationResult lambdaResult = context.InvokeClosure(closure, frame); if (lambdaResult.IsErrorValue) { return(EvaluationResult.Error); } bool isTrue = Expression.IsTruthy(lambdaResult); if (isSome && isTrue) { return(EvaluationResult.True); } if (!isSome && !isTrue) { return(EvaluationResult.False); } } // if isSome ("some") and we've exhausted the loop (no elem matched) ==> return false // if !isSome ("all") and we've exhausted the loop (all elems matched) ==> return true return(EvaluationResult.Create(!isSome)); } }
private static EvaluationResult MapDefined(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg); int paramsCount = closure.Function.Params; if (receiver.Length == 0) { return(EvaluationResult.Create(receiver)); } var result = new EvaluationResult[receiver.Length]; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { int j = 0; for (int i = 0; i < receiver.Length; ++i) { frame.TrySetArguments(paramsCount, receiver[i], i, EvaluationResult.Create(receiver)); EvaluationResult r = context.InvokeClosure(closure, frame); if (r.IsErrorValue) { return(EvaluationResult.Error); } // Skip the result if undefined. if (!r.IsUndefined) { result[j] = r; ++j; } } var definedResult = new EvaluationResult[j]; Array.Copy(result, 0, definedResult, 0, j); return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(definedResult, context.TopStack.InvocationLocation, context.TopStack.Path))); } }
private static EvaluationResult ZipWith(Context context, ArrayLiteral receiver, EvaluationResult arg0, EvaluationResult arg1, EvaluationStackFrame captures) { var arrayToZipWith = Converter.ExpectArrayLiteral(arg0); var closure = Converter.ExpectClosure(arg1); int paramsCount = closure.Function.Params; if (receiver.Length == 0) { return(EvaluationResult.Create(receiver)); } if (arrayToZipWith.Length == 0) { return(EvaluationResult.Create(arrayToZipWith)); } // The returned array has the size of the smallest array var result = new EvaluationResult[Math.Min(receiver.Length, arrayToZipWith.Length)]; using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { for (int i = 0; i < result.Length; ++i) { // zipWith callback takes 2 arguments: from the receiver and from the first argument of a zipWith function. frame.TrySetArguments(paramsCount, receiver[i], arrayToZipWith[i]); result[i] = context.InvokeClosure(closure, frame); if (result[i].IsErrorValue) { return(EvaluationResult.Error); } } return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(result, context.TopStack.InvocationLocation, context.TopStack.Path))); } }
private static EvaluationResult Sort(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { if (receiver.Length <= 1) { return(EvaluationResult.Create(receiver)); } bool hasErrors = false; var closure = Converter.ExpectClosure(arg, new ConversionContext(allowUndefined: true, pos: 1)); IEnumerable <EvaluationResult> sortedArray; if (closure == null) { EvaluationResult firstElem = receiver.Values.First(); object firstValue = firstElem.Value; if (firstValue is int) { sortedArray = receiver.Values.OrderBy(e => Converter.ExpectNumber(e, context: new ConversionContext(objectCtx: e)), Comparer <int> .Default); } else if (firstValue is string) { sortedArray = receiver.Values.OrderBy(e => Converter.ExpectString(e, context: new ConversionContext(objectCtx: e)), Comparer <string> .Default); } else { throw Converter.CreateException( expectedTypes: new[] { typeof(int), typeof(string) }, value: firstElem, context: new ConversionContext(pos: 1, objectCtx: receiver)); } } else { using (var frame = EvaluationStackFrame.Create(closure.Function, captures.Frame)) { sortedArray = receiver.Values.OrderBy(e => e, Comparer <EvaluationResult> .Create((lhs, rhs) => { if (lhs.IsErrorValue || rhs.IsErrorValue) { hasErrors = true; return(0); } frame.SetArgument(0, lhs); frame.SetArgument(1, rhs); EvaluationResult compareResult = context.InvokeClosure(closure, frame); if (compareResult.IsErrorValue) { hasErrors = true; return(0); } return(Converter.ExpectNumber(compareResult, context: new ConversionContext(objectCtx: closure))); })); } } var entry = context.TopStack; var sortedArrayMaterialized = sortedArray.ToArray(); var result = hasErrors ? (object)ErrorValue.Instance : ArrayLiteral.CreateWithoutCopy(sortedArrayMaterialized, entry.InvocationLocation, entry.Path); return(EvaluationResult.Create(result)); }
private static EvaluationResult Filter(Context context, ArrayLiteral receiver, EvaluationResult arg, EvaluationStackFrame captures) { var closure = Converter.ExpectClosure(arg); if (receiver.Length == 0) { return(EvaluationResult.Create(receiver)); } // [a,b,c].filter(x => x !== undefined) is a common pattern. // Using a specialized filtering logic improves performance. bool isSpecialUndefinedCheck = IsSpecialUndefinedCheck(closure); // The following variable contains a list of indices that changed the predicate value from true to false and vice versa. // Consider following example: // [1,2,3,4,5].filter(x => x > 3); // In this case we'll get the following values in indices variable: // [0, // starting index: assume that predicate is true at the beginning // 0, // the first element yields 'false' // 3, // 3-d index yield 'true' // 5] // will contains the size of the array if the predicate yielded 'true' at the end of the loop. // To filter the array using this table, we just need to copy all // elements in every range: 'even index' to 'even index + 1' because those ranges contains // indices when predicate yielded 'true'. // This approach saves both memory and improve perf (0.5Gb for Analog repo and even more for OneCore). // Instead of allocating another array this function will allocate the list that will be // twice as small in the worst case (when every element yields different result). List <int> indices = new List <int>() { 0 }; bool lastPredicate = true; int resultingLength = 0; int paramsCount = closure.Function.Params; // Allocating the frame. // Needed only for non-optimized version. If the predicate is just a null check, no frames were needed. using (var frame = isSpecialUndefinedCheck ? default(EvaluationStackFrame) : EvaluationStackFrame.Create(closure.Function, captures.Frame)) { int i; for (i = 0; i < receiver.Length; ++i) { EvaluationResult valueToCompare = receiver[i]; // In a better world, the following logic would be extracted in the separate method. // But in the current one it will require a method with 7-8 arguments. // So, keeping the logic right in the loop. bool predicateResult; if (isSpecialUndefinedCheck) { predicateResult = !valueToCompare.IsUndefined; } else { frame.TrySetArguments(paramsCount, receiver[i], i, EvaluationResult.Create(receiver)); valueToCompare = context.InvokeClosure(closure, frame); if (valueToCompare.IsErrorValue) { return(EvaluationResult.Error); } predicateResult = Expression.IsTruthy(valueToCompare); } if (predicateResult != lastPredicate) { lastPredicate = predicateResult; indices.Add(i); } if (predicateResult) { resultingLength++; } } if (lastPredicate) { indices.Add(i); } if (resultingLength == receiver.Length) { // Nothing was filtered. // Just returning the same result. return(EvaluationResult.Create(receiver)); } EvaluationResult[] result = resultingLength == 0 ? CollectionUtilities.EmptyArray <EvaluationResult>() : new EvaluationResult[resultingLength]; // Now we need to copy all the items from the source array int targetIndex = 0; for (int idx = 0; idx < indices.Count; idx += 2) { int sourceIndex = indices[idx]; int length = indices[idx + 1] - sourceIndex; receiver.Copy(sourceIndex, result, targetIndex, length); targetIndex += length; } return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(result, context.TopStack.InvocationLocation, context.TopStack.Path))); } }