Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
            }
        }