public static ZilObject PRINT_MANY([NotNull] Context ctx, ZilChannel channel, [Decl("<OR ATOM APPLICABLE>")] ZilObject printer, [NotNull] ZilObject[] items) { if (printer is ZilAtom atom) { printer = ctx.GetGlobalVal(atom) ?? ctx.GetLocalVal(atom); if (printer == null) { throw new InterpreterError( InterpreterMessages._0_Atom_1_Has_No_2_Value, "PRINT-MANY", atom.ToStringContext(ctx, false), "local or global"); } } var applicablePrinter = printer.AsApplicable(ctx); if (applicablePrinter == null) { throw new InterpreterError(InterpreterMessages._0_Not_Applicable_1, "PRINT-MANY", printer.ToStringContext(ctx, false)); } var crlf = ctx.GetStdAtom(StdAtom.PRMANY_CRLF); var result = ctx.TRUE; using (var innerEnv = ctx.PushEnvironment()) { innerEnv.Rebind(ctx.GetStdAtom(StdAtom.OUTCHAN), channel); var printArgs = new ZilObject[1]; foreach (var item in items) { result = item; if (result == crlf) { CRLF(ctx); } else { printArgs[0] = result; applicablePrinter.ApplyNoEval(ctx, printArgs); } } } return(result); }
static ZilResult PerformMap([NotNull] Context ctx, ZilObject finalf, IApplicable loopf, [NotNull] IStructure[] structs, bool first) { if (structs == null) { throw new ArgumentNullException(nameof(structs)); } var finalf_app = finalf.AsApplicable(ctx); int numStructs = structs.Length; var loopArgs = new ZilObject[numStructs]; var results = new List <ZilObject>(); bool running = true; while (running) { // prepare loop args int i; for (i = 0; i < numStructs; i++) { var st = structs[i]; if (st == null || st.IsEmpty) { break; } if (first) { loopArgs[i] = st.GetFirst(); } else { loopArgs[i] = (ZilObject)st; } structs[i] = st.GetRest(1); } if (i < numStructs) { break; } // apply loop function var result = loopf.ApplyNoEval(ctx, loopArgs); if (result.IsMapControl(out var outcome, out var value)) { switch (outcome) { case ZilResult.Outcome.MapStop: // add values to results and exit loop results.AddRange((IEnumerable <ZilObject>)value); running = false; continue; case ZilResult.Outcome.MapRet: // add values to results and continue results.AddRange((IEnumerable <ZilObject>)value); continue; case ZilResult.Outcome.MapLeave: // discard results, skip finalf, and return this value from the map return(value); default: throw new UnhandledCaseException(outcome.ToString()); } } if (result.ShouldPass()) { return(result); } results.Add((ZilObject)result); } // apply final function if (finalf_app != null) { return(finalf_app.ApplyNoEval(ctx, results.ToArray())); } return(results.Count > 0 ? results[results.Count - 1] : ctx.FALSE); }
public static ZilResult SORT(Context ctx, [NotNull][Decl("<OR FALSE APPLICABLE>")] ZilObject predicate, [NotNull] ZilVector vector, int recordSize = 1, int keyOffset = 0, [CanBeNull] AdditionalSortParam[] additionalSorts = null) { if (keyOffset < 0 || keyOffset >= recordSize) { throw new InterpreterError(InterpreterMessages._0_Expected_0__Key_Offset__Record_Size, "SORT"); } var vectorLength = vector.GetLength(); int numRecords = Math.DivRem(vectorLength, recordSize, out var remainder); if (remainder != 0) { throw new InterpreterError(InterpreterMessages._0_Vector_Length_Must_Be_A_Multiple_Of_Record_Size, "SORT"); } if (additionalSorts != null) { foreach (var asp in additionalSorts) { if (asp.RecordSize < 1) { throw new InterpreterError(InterpreterMessages._0_Expected_0__Key_Offset__Record_Size, "SORT"); } var len = asp.Vector.GetLength(); int recs = Math.DivRem(len, asp.RecordSize, out var rem); if (rem != 0) { throw new InterpreterError(InterpreterMessages._0_Vector_Length_Must_Be_A_Multiple_Of_Record_Size, "SORT"); } if (recs != numRecords) { throw new InterpreterError(InterpreterMessages._0_All_Vectors_Must_Have_The_Same_Number_Of_Records, "SORT"); } } } ZilObject KeySelector(int i) => vector[i * recordSize + keyOffset]; Comparison <ZilObject> comparison; if (predicate.IsTrue) { // user-provided comparison var applicable = predicate.AsApplicable(ctx); Debug.Assert(applicable != null); var args = new ZilObject[2]; comparison = (a, b) => { // greater? args[0] = a; args[1] = b; var zr = applicable.ApplyNoEval(ctx, args); if (zr.ShouldPass()) { throw new SortAbortedException(zr); } if (((ZilObject)zr).IsTrue) { return(1); } // less? args[0] = b; args[1] = a; zr = applicable.ApplyNoEval(ctx, args); if (zr.ShouldPass()) { throw new SortAbortedException(zr); } if (((ZilObject)zr).IsTrue) { return(-1); } // equal return(0); }; } else { // default comparison comparison = (a, b) => { if (a.GetTypeAtom(ctx) != b.GetTypeAtom(ctx)) { throw new InterpreterError(InterpreterMessages._0_Keys_Must_Have_The_Same_Type_To_Use_Default_Comparison, "SORT"); } a = a.GetPrimitive(ctx); b = b.GetPrimitive(ctx); switch (a.PrimType) { case PrimType.ATOM: return(string.Compare(((ZilAtom)a).Text, ((ZilAtom)b).Text, StringComparison.Ordinal)); case PrimType.FIX: return(((ZilFix)a).Value.CompareTo(((ZilFix)b).Value)); case PrimType.STRING: return(string.Compare(((ZilString)a).Text, ((ZilString)b).Text, StringComparison.Ordinal)); default: throw new InterpreterError(InterpreterMessages._0_Key_Primtypes_Must_Be_ATOM_FIX_Or_STRING_To_Use_Default_Comparison, "SORT"); } }; } try { // sort var sortedIndexes = Enumerable.Range(0, numRecords) .OrderBy(KeySelector, Comparer <ZilObject> .Create(comparison)) .ToArray(); // write output RearrangeVector(vector, recordSize, sortedIndexes); if (additionalSorts != null) { foreach (var asp in additionalSorts) { RearrangeVector(asp.Vector, asp.RecordSize, sortedIndexes); } } return(vector); } catch (SortAbortedException ex) { return(ex.ZilResult); } catch (Exception wrapper) when(wrapper.InnerException is SortAbortedException ex) { return(ex.ZilResult); } }