Пример #1
0
 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;
 }
Пример #2
0
            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));
            }
Пример #3
0
        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);
            }
        }
Пример #4
0
 protected BoundedLoop(BoundedLoopContext blc)
 {
     this.blc = blc;
 }