public static ZilResult PROG([NotNull] Context ctx, [CanBeNull][Optional] ZilAtom activationAtom, BindingParams.BindingList bindings, [CanBeNull][Optional] ZilDecl bodyDecl, [NotNull][Required] ZilObject[] body) { return(PerformProg(ctx, activationAtom, bindings, bodyDecl, body, "PROG", false, true)); }
static ZilResult PerformProg([NotNull][ProvidesContext] Context ctx, [CanBeNull] ZilAtom activationAtom, BindingParams.BindingList bindings, [CanBeNull] ZilDecl bodyDecl, [ItemNotNull][NotNull] ZilObject[] body, [NotNull] string name, bool repeat, bool catchy) { using (var activation = new ZilActivation(ctx.GetStdAtom(StdAtom.PROG))) { using (var innerEnv = ctx.PushEnvironment()) { if (activationAtom != null) { innerEnv.Rebind(activationAtom, activation); } var bodyAtomDecls = bodyDecl?.GetAtomDeclPairs().ToLookup(p => p.Key, p => p.Value); foreach (var b in bindings.Bindings) { var atom = b.Atom; var initializer = b.Initializer; ZilObject value; if (initializer != null) { var initResult = initializer.Eval(ctx); if (initResult.ShouldPass(activation, ref initResult)) { return(initResult); } value = (ZilObject)initResult; } else { value = null; } var previousDecl = b.Decl; var firstBodyDecl = bodyAtomDecls?[atom].FirstOrDefault(); if (firstBodyDecl != null && (previousDecl != null || bodyAtomDecls[atom].Skip(1).Any())) { throw new InterpreterError(InterpreterMessages._0_Conflicting_DECLs_For_Atom_1, name, atom); } var decl = previousDecl ?? firstBodyDecl; if (value != null) { ctx.MaybeCheckDecl(initializer, value, decl, "LVAL of {0}", atom); } innerEnv.Rebind(atom, value, decl); } if (catchy) { innerEnv.Rebind(ctx.EnclosingProgActivationAtom, activation); } // evaluate body ZilResult result = null; bool again; do { again = false; foreach (var expr in body) { result = expr.Eval(ctx); if (result.IsAgain(activation)) { again = true; } else if (result.ShouldPass(activation, ref result)) { return(result); } } } while (repeat || again); return(result); } } }