/// <inheritdoc /> protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame) { // Initializer is optional. EvaluationResult?initValue = Initializer?.Eval(context, env, frame); if (initValue?.IsErrorValue == true) { return(EvaluationResult.Error); } // Condition in for loops is optional. If the condition is missing, it means that it is true. EvaluationResult condValue = Condition?.Eval(context, env, frame) ?? EvaluationResult.Create(true); if (condValue.IsErrorValue) { return(EvaluationResult.Error); } // Only unit test can specify MaxloopIterations to override this setting. var maxLoopIterations = context.FrontEndHost.FrontEndConfiguration.MaxLoopIterations(); // Technically, the following implementation is not correct, because it assumes that the body is not nullable // and that condition expression should be evaluated once. // This is definitely not the case for TypeScript. int iterations = 0; while (Expression.IsTruthy(condValue)) { if (++iterations > maxLoopIterations) { context.Errors.ReportForLoopOverflow(env, Location, maxLoopIterations); return(EvaluationResult.Error); } var b = Body.Eval(context, env, frame); // If the body returns `Continue`, then do nothing! `Continue` only affects evaluation within the body, not the loop. if (b.Value == BreakValue.Instance) { break; } if (b.IsErrorValue || frame.ReturnStatementWasEvaluated) { // Got the error, or 'return' expression was reached. return(b); } var incValue = Incrementor?.Eval(context, env, frame); if (incValue?.IsErrorValue == true) { return(EvaluationResult.Error); } condValue = Condition?.Eval(context, env, frame) ?? EvaluationResult.Create(true); if (condValue.IsErrorValue) { return(condValue); } } return(EvaluationResult.Undefined); }