Example #1
0
        /// <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);
        }