public Loop(BoundedLoopContext blc, ZilAtom atom, ZilObject start, ZilObject end, ZilObject inc) : base(blc) { this.atom = atom; this.start = start; this.end = end; this.inc = inc; }
public IBoundedLoop MakeLoop(BoundedLoopContext blc) { if (!blc.spec.HasLength(3, 4)) { throw new CompilerError( blc.src, CompilerMessages._0_Expected_1_Element1s_In_Binding_List, Name, new CountableString("3 or 4", true)); } if (!blc.spec.Matches(out ZilAtom atom, out ZilObject start, out ZilObject end, out ZilObject inc) && !blc.spec.Matches(out atom, out start, out end)) { throw new CompilerError( blc.src, CompilerMessages._0_1_Element_In_Binding_List_Must_Be_2, Name, "first", "an atom"); } return(new Loop(blc, atom, start, end, inc)); }
private IOperand CompileBoundedLoop( [NotNull] IRoutineBuilder rb, [NotNull] IBoundedLoopBuilder builder, [NotNull] ZilListoidBase args, [NotNull] ISourceLine src, bool wantResult, [CanBeNull] IVariable resultStorage) { // extract loop spec ("binding list", although we don't care about the bindings here) // TODO: allow activation atoms in bounded loops? if (!args.IsCons(out var first, out var rest) || !(first is ZilList spec)) { throw new CompilerError(CompilerMessages.Expected_Binding_List_At_Start_Of_0, builder.Name); } // instantiate the loop and let it check binding syntax var blc = new BoundedLoopContext(this, spec, src); using (var loop = builder.MakeLoop(blc)) { // look for the optional end statements ZilListoidBase body; if (rest.StartsWith(out ZilList endStmts)) { (_, body) = rest; } else { body = rest; } // create block resultStorage = wantResult ? (resultStorage ?? rb.Stack) : null; var block = new Block { AgainLabel = rb.DefineLabel(), ResultStorage = resultStorage, ReturnLabel = rb.DefineLabel(), Flags = wantResult ? BlockFlags.WantResult : 0 }; Blocks.Push(block); try { var exhaustedLabel = rb.DefineLabel(); // let the loop initialize counters, etc. loop.BeforeBlock(rb, block, exhaustedLabel); // mark the top of the block ("again" label) and let the loop add prechecks, etc. rb.MarkLabel(block.AgainLabel); loop.BeforeBody(); // compile the body CompileClauseBody(rb, body, false, null); // let the loop add postchecks, etc., and mark the end of the block ("exhausted" label) loop.AfterBody(); rb.MarkLabel(exhaustedLabel); // compile the end statements if present, and provide a return value if requested if (endStmts != null) { CompileClauseBody(rb, endStmts, false, null); } if (wantResult) { rb.EmitStore(resultStorage, Game.One); } // if <RETURN> was used inside the loop, mark the return label if ((block.Flags & BlockFlags.Returned) != 0) { rb.MarkLabel(block.ReturnLabel); } } finally { Blocks.Pop(); } return(wantResult ? resultStorage : null); } }
protected BoundedLoop(BoundedLoopContext blc) { this.blc = blc; }