internal void ExpandInPlace([NotNull] Context ctx) { IEnumerable <ZilObject> RecursiveExpandWithSplice(ZilObject zo) { ZilObject result; ZilObject SetSourceLine(ZilResult zr) { var newObj = (ZilObject)zr; newObj.SourceLine = zo.SourceLine; return(newObj); } switch (zo) { case ZilList list: result = new ZilList(list.SelectMany(RecursiveExpandWithSplice)); break; case ZilVector vector: result = new ZilVector(vector.SelectMany(RecursiveExpandWithSplice).ToArray()); break; case ZilForm form: ZilObject expanded; try { using (DiagnosticContext.Push(form.SourceLine)) { expanded = (ZilObject)form.Expand(ctx); } } catch (InterpreterError ex) { ctx.HandleError(ex); return(new[] { ctx.FALSE }); } if (expanded is IMayExpandAfterEvaluation expandAfter && expandAfter.ShouldExpandAfterEvaluation) { return(expandAfter.ExpandAfterEvaluation().AsResultSequence() .Select(SetSourceLine) .Select(xo => ReferenceEquals(xo, form) ? xo : new ZilMacroResult(xo))); } else if (!ReferenceEquals(expanded, form)) { expanded.SourceLine = zo.SourceLine; return(RecursiveExpandWithSplice(expanded) .Select(xo => new ZilMacroResult(xo))); } else { result = new ZilForm(form.SelectMany(RecursiveExpandWithSplice)); } break;
static void RearrangeVector([NotNull] ZilVector vector, int recordSize, [NotNull] int[] desiredIndexOrder) { var output = new List <ZilObject>(vector.GetLength()); foreach (var srcIndex in desiredIndexOrder) { for (int i = 0; i < recordSize; i++) { output.Add(vector[srcIndex * recordSize + i]); } } for (int i = 0; i < output.Count; i++) { vector[i] = output[i]; } }
public void TestDEFSTRUCT_ExistingObject() { var ctx = new Context(); var pointAtom = ZilAtom.Parse("POINT", ctx); TestHelpers.EvalAndAssert(ctx, "<DEFSTRUCT POINT VECTOR (POINT-X FIX 0) (POINT-Y FIX 0) (POINT-Z FIX 0) (POINT-W FIX 'NONE)>", pointAtom); // put values into existing object, setting any omitted fields to default values (unless the default is NONE!) var vector = new ZilVector(new ZilFix(123), new ZilFix(456), new ZilFix(789), new ZilFix(1011)); ctx.SetLocalVal(ZilAtom.Parse("MY-VECTOR", ctx), new ZilStructuredHash(pointAtom, PrimType.VECTOR, vector)); TestHelpers.EvalAndAssert(ctx, "<MAKE-POINT 'POINT .MY-VECTOR 'POINT-Y 999 'POINT-X 888>", new ZilStructuredHash(pointAtom, PrimType.VECTOR, vector)); TestHelpers.AssertStructurallyEqual(new ZilFix(888), vector[0]); TestHelpers.AssertStructurallyEqual(new ZilFix(999), vector[1]); TestHelpers.AssertStructurallyEqual(new ZilFix(0), vector[2]); TestHelpers.AssertStructurallyEqual(new ZilFix(1011), vector[3]); }
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); } }