Пример #1
0
        private CSharpName GetEarlyExitNameIfRequired(DoBlock doBlock, ScopeAccessInformation scopeAccessInformation)
        {
            if (doBlock == null)
            {
                throw new ArgumentNullException("doBlock");
            }
            if (scopeAccessInformation == null)
            {
                throw new ArgumentNullException("scopeAccessInformation");
            }

            if (!doBlock.SupportsExit || !doBlock.ContainsLoopThatContainsMismatchedExitThatMustBeHandledAtThisLevel())
            {
                return(null);
            }

            return(_tempNameGenerator(new CSharpName("exitDo"), scopeAccessInformation));
        }
Пример #2
0
        public TranslationResult Translate(DoBlock doBlock, ScopeAccessInformation scopeAccessInformation, int indentationDepth)
        {
            if (doBlock == null)
            {
                throw new ArgumentNullException("doBlock");
            }
            if (scopeAccessInformation == null)
            {
                throw new ArgumentNullException("scopeAccessInformation");
            }
            if (indentationDepth < 0)
            {
                throw new ArgumentOutOfRangeException("indentationDepth", "must be zero or greater");
            }

            if ((doBlock.ConditionIfAny == null) && !doBlock.Statements.Any())
            {
                _logger.Warning("Infinite DO/WHILE loop at line " + (doBlock.LineIndexOfStartOfConstruct + 1));
                return(TranslationResult.Empty.Add(new TranslatedStatement(
                                                       "while (true) { }",
                                                       indentationDepth,
                                                       doBlock.LineIndexOfStartOfConstruct
                                                       )));
            }

            var earlyExitNameIfAny = GetEarlyExitNameIfRequired(doBlock, scopeAccessInformation);
            var loopStatementsTranslationResult = Translate(
                doBlock.Statements.ToNonNullImmutableList(),
                scopeAccessInformation.SetParent(doBlock),
                doBlock.SupportsExit,
                earlyExitNameIfAny,
                indentationDepth + 1
                );

            TranslatedStatementContentDetails whileConditionExpressionContentIfAny;

            if (doBlock.ConditionIfAny == null)
            {
                whileConditionExpressionContentIfAny = null;
            }
            else
            {
                whileConditionExpressionContentIfAny = _statementTranslator.Translate(
                    doBlock.ConditionIfAny,
                    scopeAccessInformation,
                    ExpressionReturnTypeOptions.Boolean,
                    _logger.Warning
                    );
                if (!doBlock.IsDoWhileCondition)
                {
                    // C# doesn't support "DO UNTIL x" but it's equivalent to "DO WHILE !x"
                    whileConditionExpressionContentIfAny = new TranslatedStatementContentDetails(
                        "!" + whileConditionExpressionContentIfAny.TranslatedContent,
                        whileConditionExpressionContentIfAny.VariablesAccessed
                        );
                }
                if (scopeAccessInformation.ErrorRegistrationTokenIfAny != null)
                {
                    // Ensure that the frankly ludicrous VBScript error-handling is applied where required. As the IProvideVBScriptCompatFunctionality's IF method
                    // signature describes, if an error occurs in retrieving the value, it will be evaluated as true. So, given a function
                    //
                    //   FUNCTION GetValue()
                    //     Err.Raise vbObjectError, "Test", "Test"
                    //   END FUNCTION
                    //
                    // both of the following loops will be entered:
                    //
                    //   ON ERROR RESUME NEXT
                    //   DO WHILE GetValue()
                    //     WScript.Echo "True"
                    //     EXIT DO
                    //   LOOP
                    //
                    //   ON ERROR RESUME NEXT
                    //   DO UNTIL GetValue()
                    //     WScript.Echo "True"
                    //     EXIT DO
                    //   LOOP
                    //
                    // This is why an additional IF call must be wrapped around the IF above - since the negation of a DO UNTIL (as opposed to a DO WHILE) loop
                    // must be within the outer, error-handling IF call. (A simpler example of the above is to replace the GetValue() call with 1/0, which will
                    // result in a "Division by zero" error if ON ERROR RESUME NEXT is not present, but which will result in both of the above loops being
                    // entered if it IS present).
                    whileConditionExpressionContentIfAny = new TranslatedStatementContentDetails(
                        string.Format(
                            "{0}.IF(() => {1}, {2})",
                            _supportRefName.Name,
                            whileConditionExpressionContentIfAny.TranslatedContent,
                            scopeAccessInformation.ErrorRegistrationTokenIfAny.Name
                            ),
                        whileConditionExpressionContentIfAny.VariablesAccessed
                        );
                }
            }

            var translationResult = TranslationResult.Empty;

            if (whileConditionExpressionContentIfAny != null)
            {
                translationResult = translationResult.AddUndeclaredVariables(
                    whileConditionExpressionContentIfAny.GetUndeclaredVariablesAccessed(scopeAccessInformation, _nameRewriter)
                    );
            }

            if (whileConditionExpressionContentIfAny == null)
            {
                translationResult = translationResult.Add(new TranslatedStatement(
                                                              "while (true)",
                                                              indentationDepth,
                                                              doBlock.LineIndexOfStartOfConstruct
                                                              ));
            }
            else if (doBlock.IsPreCondition)
            {
                translationResult = translationResult.Add(new TranslatedStatement(
                                                              "while (" + whileConditionExpressionContentIfAny.TranslatedContent + ")",
                                                              indentationDepth,
                                                              doBlock.LineIndexOfStartOfConstruct
                                                              ));
            }
            else
            {
                translationResult = translationResult.Add(new TranslatedStatement(
                                                              "do",
                                                              indentationDepth,
                                                              doBlock.LineIndexOfStartOfConstruct
                                                              ));
            }
            translationResult = translationResult.Add(new TranslatedStatement("{", indentationDepth, doBlock.LineIndexOfStartOfConstruct));
            if (earlyExitNameIfAny != null)
            {
                translationResult = translationResult.Add(new TranslatedStatement(
                                                              string.Format("var {0} = false;", earlyExitNameIfAny.Name),
                                                              indentationDepth + 1,
                                                              doBlock.LineIndexOfStartOfConstruct
                                                              ));
            }
            translationResult = translationResult.Add(loopStatementsTranslationResult);
            var lineIndexForClosingCode = loopStatementsTranslationResult.TranslatedStatements.Any()
                                ? loopStatementsTranslationResult.TranslatedStatements.Last().LineIndexOfStatementStartInSource
                                : doBlock.LineIndexOfStartOfConstruct;

            if ((whileConditionExpressionContentIfAny == null) || doBlock.IsPreCondition)
            {
                translationResult = translationResult.Add(new TranslatedStatement("}", indentationDepth, lineIndexForClosingCode));
            }
            else
            {
                translationResult = translationResult.Add(new TranslatedStatement(
                                                              "} while (" + whileConditionExpressionContentIfAny.TranslatedContent + ");",
                                                              indentationDepth,
                                                              doBlock.ConditionIfAny.Tokens.First().LineIndex
                                                              ));
            }
            var earlyExitFlagNamesToCheck = scopeAccessInformation.StructureExitPoints
                                            .Where(e => e.ExitEarlyBooleanNameIfAny != null)
                                            .Select(e => e.ExitEarlyBooleanNameIfAny.Name);

            if (earlyExitFlagNamesToCheck.Any())
            {
                // These lines do not directly have equivalents in the source, so just take the line index of the previous line that was generated
                // by the above code
                var lineIndexForEarlyExitCode = translationResult.TranslatedStatements.Last().LineIndexOfStatementStartInSource;

                // Perform early-exit checks for any scopeAccessInformation.StructureExitPoints - if this is DO..LOOP loop inside a FOR loop and an
                // EXIT FOR was encountered within the DO..LOOP that must refer to the containing FOR, then the DO..LOOP will have been broken out
                // of, but also a flag set that means that we must break further to get out of the FOR loop.
                translationResult = translationResult
                                    .Add(new TranslatedStatement(
                                             "if (" + string.Join(" || ", earlyExitFlagNamesToCheck) + ")",
                                             indentationDepth,
                                             lineIndexForEarlyExitCode
                                             ))
                                    .Add(new TranslatedStatement(
                                             "break;",
                                             indentationDepth + 1,
                                             lineIndexForEarlyExitCode
                                             ));
            }
            return(translationResult);
        }