예제 #1
0
        public object VisitIfStatement(JsIfStatement statement, bool addNewline)
        {
redo:
            _cb.Append("if").Append(_space + "(");
            VisitExpression(statement.Test, false);
            _cb.Append(")" + _space);
            VisitStatement(statement.Then, !_minify && (statement.Else != null || addNewline));
            if (statement.Else != null)
            {
                _cb.Append("else");
                if (statement.Else.Statements.Count == 1 && statement.Else.Statements[0] is JsIfStatement)
                {
                    _cb.Append(" ");
                    statement = (JsIfStatement)statement.Else.Statements[0];
                    goto redo;
                }
                else
                {
                    _cb.Append(_space);
                }
            }

            if (statement.Else != null)
            {
                VisitStatement(statement.Else, addNewline);
            }

            return(null);
        }
        public virtual JsStatement VisitIfStatement(JsIfStatement statement, TData data)
        {
            var test  = VisitExpression(statement.Test, data);
            var then  = VisitStatement(statement.Then, data);
            var @else = statement.Else != null?VisitStatement(statement.Else, data) : null;

            return(ReferenceEquals(test, statement.Test) && ReferenceEquals(then, statement.Then) && ReferenceEquals(@else, statement.Else) ? statement : new JsIfStatement(test, then, @else));
        }
예제 #3
0
 public virtual void Visit(JsIfStatement node)
 {
     DefaultVisit(node);
     node.Condition.Accept(this);
     node.IfTrue.Accept(this);
     if (node.IfFalse != null)
     {
         node.IfFalse.Accept(this);
     }
 }
예제 #4
0
 public override void VisitIfStatement(JsIfStatement node)
 {
     output.Append("if (");
     node.Condition.Accept(this);
     output.Append(")");
     WriteMaybeBlock(node.IfTrue, true);
     if (node.IfFalse != null)
     {
         output.Append("else");
         WriteMaybeBlock(node.IfFalse, true);
     }
 }
예제 #5
0
 public virtual JsNode Visit(JsIfStatement node)
 {
     return(DefaultVisit(node, x =>
     {
         x.Condition = (JsExpression)x.Condition.Accept(this);
         x.IfTrue = (JsStatement)x.IfTrue.Accept(this);
         if (x.IfFalse != null)
         {
             x.IfFalse = (JsStatement)x.IfFalse.Accept(this);
         }
         return x;
     }));
 }
예제 #6
0
        private bool HandleIfStatement(JsIfStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock)
        {
            var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState);

            IList <JsStatement> thenPart, elsePart;

            if (stmt.Then.Statements.Count == 0)
            {
                thenPart = EmptyList <JsStatement> .Instance;
            }
            else
            {
                thenPart = Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(stmt.Then, 0)), breakStack, continueStack, currentState, stateAfter.Item1, false, false);
            }

            if (stmt.Else == null)
            {
                elsePart = null;
            }
            else if (stmt.Else.Statements.Count == 0)
            {
                elsePart = EmptyList <JsStatement> .Instance;
            }
            else
            {
                elsePart = Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(stmt.Else, 0)), breakStack, continueStack, currentState, stateAfter.Item1, false, false);
            }

            currentBlock.Add(JsStatement.If(stmt.Test, JsStatement.Block(thenPart), elsePart != null ? JsStatement.Block(elsePart) : null));
            if (thenPart.Count == 0 || elsePart == null || elsePart.Count == 0)
            {
                currentBlock.Add(new JsGotoStateStatement(stateAfter.Item1, currentState));
            }

            if (stateAfter.Item2)
            {
                Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState);
                return(false);
            }

            return(true);
        }
예제 #7
0
        private bool HandleIfStatement(JsIfStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock)
        {
            var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState);

            var thenPart = Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(stmt.Then, 0)), breakStack, continueStack, currentState, stateAfter.Item1);
            var elsePart = stmt.Else != null?Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(stmt.Else, 0)), breakStack, continueStack, currentState, stateAfter.Item1) : null;

            currentBlock.Add(new JsIfStatement(stmt.Test, new JsBlockStatement(thenPart), elsePart != null ? new JsBlockStatement(elsePart) : null));
            if (elsePart == null)
            {
                currentBlock.Add(new JsGotoStateStatement(stateAfter.Item1, currentState));
            }

            if (stateAfter.Item2)
            {
                Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState);
                return(false);
            }

            return(true);
        }
        private JsBlockStatement GenerateUsingBlock(LocalResolveResult resource, Expression aquisitionExpression, DomRegion tempVariableRegion, JsBlockStatement body)
        {
            SetRegion(aquisitionExpression.GetRegion());
            var boolType = _compilation.FindType(KnownTypeCode.Boolean);
            var systemIDisposable = _compilation.FindType(KnownTypeCode.IDisposable);
            var disposeMethod = systemIDisposable.GetMethods().Single(m => m.Name == "Dispose");
            var conversions = CSharpConversions.Get(_compilation);

            var compiledAquisition = CompileExpression(aquisitionExpression, true);

            var stmts = new List<JsStatement>();
            stmts.AddRange(compiledAquisition.AdditionalStatements);
            stmts.Add(new JsVariableDeclarationStatement(new JsVariableDeclaration(_variables[resource.Variable].Name, compiledAquisition.Expression)));

            bool isDynamic = resource.Type.Kind == TypeKind.Dynamic;

            if (isDynamic) {
                var newResource = CreateTemporaryVariable(systemIDisposable, tempVariableRegion);
                var castExpr = _expressionCompiler.Compile(new ConversionResolveResult(systemIDisposable, resource, conversions.ExplicitConversion(resource, systemIDisposable)), true);
                stmts.AddRange(castExpr.AdditionalStatements);
                stmts.Add(new JsVariableDeclarationStatement(new JsVariableDeclaration(_variables[newResource].Name, castExpr.Expression)));
                resource = new LocalResolveResult(newResource);
            }

            var compiledDisposeCall = _expressionCompiler.Compile(
                                          new CSharpInvocationResolveResult(
                                              new ConversionResolveResult(systemIDisposable, resource, conversions.ImplicitConversion(resource, systemIDisposable)),
                                              disposeMethod,
                                              new ResolveResult[0]
                                          ), false);
            if (compiledDisposeCall.AdditionalStatements.Count > 0)
                _errorReporter.InternalError("Type test cannot return additional statements.");

            JsStatement releaseStmt;
            if (isDynamic) {
                releaseStmt = new JsExpressionStatement(compiledDisposeCall.Expression);
            }
            else {
                // if (d != null) ((IDisposable)d).Dispose()
                var compiledTest = _expressionCompiler.Compile(new OperatorResolveResult(boolType, ExpressionType.NotEqual, resource, new ConstantResolveResult(resource.Type, null)), true);
                if (compiledTest.AdditionalStatements.Count > 0)
                    _errorReporter.InternalError("Null test cannot return additional statements.");
                releaseStmt = new JsIfStatement(compiledTest.Expression, new JsExpressionStatement(compiledDisposeCall.Expression), null);
            }

            stmts.Add(new JsTryStatement(body, null, releaseStmt));

            return new JsBlockStatement(stmts);
        }
        public override void VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
        {
            var tryBlock = CreateInnerCompiler().Compile(tryCatchStatement.TryBlock);
            JsCatchClause catchClause = null;
            if (tryCatchStatement.CatchClauses.Count > 0) {
                var oldVariableForRethrow = _currentVariableForRethrow;

                _currentVariableForRethrow = CreateTemporaryVariable(_compilation.FindType(KnownTypeCode.Object), tryCatchStatement.CatchClauses.First().GetRegion());
                string catchVariableName = _variables[_currentVariableForRethrow].Name;

                var catchClauses = tryCatchStatement.CatchClauses.ToList();
                var systemException = _compilation.FindType(KnownTypeCode.Exception);
                RemoveCatchClausesAfterExceptionType(catchClauses, systemException);

                bool lastIsCatchall = (catchClauses[catchClauses.Count - 1].Type.IsNull || _resolver.Resolve(catchClauses[catchClauses.Count - 1].Type).Type.Equals(systemException));
                JsStatement current = lastIsCatchall
                                    ? CompileCatchClause(new LocalResolveResult(_currentVariableForRethrow), catchClauses[catchClauses.Count - 1], true, catchClauses.Count == 1)
                                    : new JsBlockStatement(new JsThrowStatement(JsExpression.Identifier(catchVariableName)));

                for (int i = catchClauses.Count - (lastIsCatchall ? 2 : 1); i >= 0; i--) {
                    var test = _runtimeLibrary.TypeIs(JsExpression.Identifier(catchVariableName), _currentVariableForRethrow.Type, _resolver.Resolve(catchClauses[i].Type).Type);
                    current = new JsIfStatement(test, CompileCatchClause(new LocalResolveResult(_currentVariableForRethrow), catchClauses[i], false, catchClauses.Count == 1), current);
                }

                if (!lastIsCatchall || catchClauses.Count > 1) {
                    // We need to wrap the exception.
                    current = new JsBlockStatement(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(catchVariableName), _runtimeLibrary.MakeException(JsExpression.Identifier(catchVariableName)))), current);
                }

                catchClause = new JsCatchClause(catchVariableName, current);
                _currentVariableForRethrow = oldVariableForRethrow;
            }

            var finallyBlock = (!tryCatchStatement.FinallyBlock.IsNull ? CreateInnerCompiler().Compile(tryCatchStatement.FinallyBlock) : null);

            _result.Add(new JsTryStatement(tryBlock, catchClause, finallyBlock));
        }
        public override void VisitForeachStatement(ForeachStatement foreachStatement)
        {
            var ferr = (ForEachResolveResult)_resolver.Resolve(foreachStatement);
            var iterator = (LocalResolveResult)_resolver.Resolve(foreachStatement.VariableNameToken);

            var systemArray = _compilation.FindType(KnownTypeCode.Array);
            var inExpression = ResolveWithConversion(foreachStatement.InExpression);
            if (Equals(inExpression.Type, systemArray) || inExpression.Type.DirectBaseTypes.Contains(systemArray)) {
                var arrayResult = CompileExpression(foreachStatement.InExpression, true);
                _result.AddRange(arrayResult.AdditionalStatements);
                var array = arrayResult.Expression;
                if (ExpressionCompiler.IsJsExpressionComplexEnoughToGetATemporaryVariable.Process(array)) {
                    var tmpArray = CreateTemporaryVariable(ferr.CollectionType, foreachStatement.GetRegion());
                    _result.Add(new JsVariableDeclarationStatement(_variables[tmpArray].Name, array));
                    array = JsExpression.Identifier(_variables[tmpArray].Name);
                }

                var length = systemArray.GetProperties().SingleOrDefault(p => p.Name == "Length");
                if (length == null) {
                    _errorReporter.InternalError("Property Array.Length not found.");
                    return;
                }
                var lengthSem = _metadataImporter.GetPropertySemantics(length);
                if (lengthSem.Type != PropertyScriptSemantics.ImplType.Field) {
                    _errorReporter.InternalError("Property Array.Length is not implemented as a field.");
                    return;
                }

                var index = CreateTemporaryVariable(_compilation.FindType(KnownTypeCode.Int32), foreachStatement.GetRegion());
                var jsIndex = JsExpression.Identifier(_variables[index].Name);
                var body = new[] { new JsVariableDeclarationStatement(_variables[iterator.Variable].Name, JsExpression.Index(array, jsIndex)) }
                          .Concat(CreateInnerCompiler().Compile(foreachStatement.EmbeddedStatement).Statements);

                _result.Add(new JsForStatement(new JsVariableDeclarationStatement(_variables[index].Name, JsExpression.Number(0)),
                                               JsExpression.Lesser(jsIndex, JsExpression.MemberAccess(array, lengthSem.FieldName)),
                                               JsExpression.PostfixPlusPlus(jsIndex),
                                               new JsBlockStatement(body)));
            }
            else {
                var getEnumeratorCall = _expressionCompiler.Compile(ferr.GetEnumeratorCall, true);
                _result.AddRange(getEnumeratorCall.AdditionalStatements);
                var enumerator = CreateTemporaryVariable(ferr.EnumeratorType, foreachStatement.GetRegion());
                _result.Add(new JsVariableDeclarationStatement(new JsVariableDeclaration(_variables[enumerator].Name, getEnumeratorCall.Expression)));

                var moveNextInvocation = _expressionCompiler.Compile(new CSharpInvocationResolveResult(new LocalResolveResult(enumerator), ferr.MoveNextMethod, new ResolveResult[0]), true);
                if (moveNextInvocation.AdditionalStatements.Count > 0)
                    _errorReporter.InternalError("MoveNext() invocation is not allowed to require additional statements.");

                var getCurrent = _expressionCompiler.Compile(new MemberResolveResult(new LocalResolveResult(enumerator), ferr.CurrentProperty), true);
                var preBody = getCurrent.AdditionalStatements.Concat(new[] { new JsVariableDeclarationStatement(new JsVariableDeclaration(_variables[iterator.Variable].Name, getCurrent.Expression)) }).ToList();
                var body = CreateInnerCompiler().Compile(foreachStatement.EmbeddedStatement);

                body = new JsBlockStatement(preBody.Concat(body.Statements));

                JsStatement disposer;

                var systemIDisposable = _compilation.FindType(KnownTypeCode.IDisposable);
                var disposeMethod = systemIDisposable.GetMethods().Single(m => m.Name == "Dispose");
                var conversions = CSharpConversions.Get(_compilation);
                var disposableConversion = conversions.ImplicitConversion(enumerator.Type, systemIDisposable);
                if (disposableConversion.IsValid) {
                    // If the enumerator is implicitly convertible to IDisposable, we should dispose it.
                    var compileResult = _expressionCompiler.Compile(new CSharpInvocationResolveResult(new ConversionResolveResult(systemIDisposable, new LocalResolveResult(enumerator), disposableConversion), disposeMethod, new ResolveResult[0]), false);
                    if (compileResult.AdditionalStatements.Count != 0)
                        _errorReporter.InternalError("Call to IDisposable.Dispose must not return additional statements.");
                    disposer = new JsExpressionStatement(compileResult.Expression);
                }
                else if (enumerator.Type.GetDefinition().IsSealed) {
                    // If the enumerator is sealed and not implicitly convertible to IDisposable, we need not dispose it.
                    disposer = null;
                }
                else {
                    // We don't know whether the enumerator is convertible to IDisposable, so we need to conditionally dispose it.
                    var test = _expressionCompiler.Compile(new TypeIsResolveResult(new LocalResolveResult(enumerator), systemIDisposable, _compilation.FindType(KnownTypeCode.Boolean)), true);
                    if (test.AdditionalStatements.Count > 0)
                        _errorReporter.InternalError("\"is\" test must not return additional statements.");
                    var innerStatements = _expressionCompiler.Compile(new CSharpInvocationResolveResult(new ConversionResolveResult(systemIDisposable, new LocalResolveResult(enumerator), conversions.ExplicitConversion(enumerator.Type, systemIDisposable)), disposeMethod, new ResolveResult[0]), false);
                    disposer = new JsIfStatement(test.Expression, new JsBlockStatement(innerStatements.AdditionalStatements.Concat(new[] { new JsExpressionStatement(innerStatements.Expression) })), null);
                }
                JsStatement stmt = new JsWhileStatement(moveNextInvocation.Expression, body);
                if (disposer != null)
                    stmt = new JsTryStatement(stmt, null, disposer);
                _result.Add(stmt);
            }
        }
예제 #11
0
        private bool HandleTryStatement(JsTryStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock)
        {
            if (_isIteratorBlock && (FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement, InterestingConstruct.YieldReturn) || (stmt.Finally != null && stmt.Catch == null && !currentState.FinallyStack.IsEmpty)))
            {
                if (stmt.Catch != null)
                {
                    throw new InvalidOperationException("Cannot yield return from try with catch");
                }
                string           handlerName = _allocateFinallyHandler();
                JsBlockStatement handler;
                if (FindInterestingConstructsVisitor.Analyze(stmt.Finally, InterestingConstruct.Label))
                {
                    var inner = ProcessInner(stmt.Finally, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue);
                    handler = new JsBlockStatement(new[]  { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1));
                    handler = new FinalizerRewriter(_stateVariableName, _labelStates).Process(handler);
                }
                else
                {
                    handler = stmt.Finally;
                }

                _finallyHandlers.Add(Tuple.Create(handlerName, handler));
                var stateAfter         = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState);
                var innerState         = CreateNewStateValue(currentState.FinallyStack, handlerName);
                var stateBeforeFinally = CreateNewStateValue(innerState.FinallyStack);
                currentBlock.Add(new JsSetNextStateStatement(innerState.StateValue));
                currentBlock.AddRange(Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(stmt.GuardedStatement, 0)), breakStack, continueStack, innerState, stateBeforeFinally));

                Enqueue(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(new JsBlockStatement(new JsBlockStatement(new JsStatement[0], true)), 0)), breakStack, continueStack, stateBeforeFinally, stateAfter.Item1);
                if (!stack.IsEmpty || location.Index < location.Block.Statements.Count - 1)
                {
                    Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState);
                }
                return(false);
            }
            else if (_isIteratorBlock && stmt.Finally != null && !currentState.FinallyStack.IsEmpty)
            {
                // This is necessary to special-case in order to ensure that the inner finally block is executed before all outer ones.
                return(HandleTryStatement(new JsTryStatement(new JsTryStatement(stmt.GuardedStatement, stmt.Catch, null), null, stmt.Finally), location, stack, breakStack, continueStack, currentState, returnState, currentBlock));
            }
            else
            {
                var rewriter = new NestedJumpStatementRewriter(breakStack, continueStack, currentState, _exitState.Value);
                JsBlockStatement guarded;
                var guardedConstructs = FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement);
                if ((guardedConstructs & (InterestingConstruct.Label | InterestingConstruct.Await)) != InterestingConstruct.None)
                {
                    var inner = ProcessInner(stmt.GuardedStatement, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue);
                    guarded = new JsBlockStatement(inner.Item1);
                    currentBlock.Add(new JsSetNextStateStatement(inner.Item2));
                }
                else
                {
                    guarded = rewriter.Process(stmt.GuardedStatement);
                }

                JsCatchClause @catch;
                if (stmt.Catch != null)
                {
                    if (FindInterestingConstructsVisitor.Analyze(stmt.Catch.Body, InterestingConstruct.Label))
                    {
                        var inner = ProcessInner(stmt.Catch.Body, breakStack, continueStack, currentState.FinallyStack, null);
                        @catch = new JsCatchClause(stmt.Catch.Identifier, new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1)));
                    }
                    else
                    {
                        var body = rewriter.Process(stmt.Catch.Body);
                        @catch = ReferenceEquals(body, stmt.Catch.Body) ? stmt.Catch : new JsCatchClause(stmt.Catch.Identifier, body);
                    }
                }
                else
                {
                    @catch = null;
                }

                JsBlockStatement @finally;
                if (stmt.Finally != null)
                {
                    if (FindInterestingConstructsVisitor.Analyze(stmt.Finally, InterestingConstruct.Label))
                    {
                        var inner = ProcessInner(stmt.Finally, breakStack, continueStack, currentState.FinallyStack, null);
                        @finally = new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1));
                    }
                    else
                    {
                        @finally = rewriter.Process(stmt.Finally);
                    }

                    if ((guardedConstructs & InterestingConstruct.Await) != InterestingConstruct.None)
                    {
                        // Wrap the finally block inside an 'if (doFinallyBlocks) {}'
                        @finally = new JsBlockStatement(new JsIfStatement(JsExpression.Identifier(_doFinallyBlocksVariableName), @finally, null));
                    }
                }
                else
                {
                    @finally = null;
                }

                if (currentBlock.Count > 0 && _childStates.ContainsKey(currentState.StateValue))
                {
                    var newBlock = new JsIfStatement(JsExpression.Same(JsExpression.Identifier(_stateVariableName), JsExpression.Number(currentState.StateValue)), new JsBlockStatement(currentBlock), null);
                    currentBlock.Clear();
                    currentBlock.Add(newBlock);
                }

                currentBlock.Add(new JsTryStatement(guarded, @catch, @finally));
                return(true);
            }
        }
        private bool HandleIfStatement(JsIfStatement stmt, StackEntry location, ImmutableStack<StackEntry> stack, ImmutableStack<Tuple<string, State>> breakStack, ImmutableStack<Tuple<string, State>> continueStack, State currentState, State returnState, IList<JsStatement> currentBlock)
        {
            var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState);

            var thenPart = Handle(ImmutableStack<StackEntry>.Empty.Push(new StackEntry(stmt.Then, 0)), breakStack, continueStack, currentState, stateAfter.Item1);
            var elsePart = stmt.Else != null ? Handle(ImmutableStack<StackEntry>.Empty.Push(new StackEntry(stmt.Else, 0)), breakStack, continueStack, currentState, stateAfter.Item1) : null;

            currentBlock.Add(new JsIfStatement(stmt.Test, new JsBlockStatement(thenPart), elsePart != null ? new JsBlockStatement(elsePart) : null));
            if (elsePart == null)
                currentBlock.Add(new JsGotoStateStatement(stateAfter.Item1, currentState));

            if (stateAfter.Item2) {
                Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState);
                return false;
            }

            return true;
        }
		private bool HandleIfStatement(JsIfStatement stmt, StackEntry location, ImmutableStack<StackEntry> stack, ImmutableStack<Tuple<string, State>> breakStack, ImmutableStack<Tuple<string, State>> continueStack, State currentState, State returnState, IList<JsStatement> currentBlock) {
			var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState);

			IList<JsStatement> thenPart, elsePart;
			if (stmt.Then.Statements.Count == 0)
				thenPart = EmptyList<JsStatement>.Instance;
			else
				thenPart = Handle(ImmutableStack<StackEntry>.Empty.Push(new StackEntry(stmt.Then, 0)), breakStack, continueStack, currentState, stateAfter.State, false, false);

			if (stmt.Else == null)
				elsePart = null;
			else if (stmt.Else.Statements.Count == 0)
				elsePart = EmptyList<JsStatement>.Instance;
			else
				elsePart = Handle(ImmutableStack<StackEntry>.Empty.Push(new StackEntry(stmt.Else, 0)), breakStack, continueStack, currentState, stateAfter.State, false, false);

			currentBlock.Add(JsStatement.If(stmt.Test, JsStatement.Block(thenPart), elsePart != null ? JsStatement.Block(elsePart) : null));
			if (thenPart.Count == 0 || elsePart == null || elsePart.Count == 0)
				currentBlock.Add(new JsGotoStateStatement(stateAfter.State, currentState));

			if (stateAfter.NeedEnqueue) {
				Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.State, returnState);
				return false;
			}

			return true;
		}
		private bool HandleTryStatement(JsTryStatement stmt, StackEntry location, ImmutableStack<StackEntry> stack, ImmutableStack<Tuple<string, State>> breakStack, ImmutableStack<Tuple<string, State>> continueStack, State currentState, State returnState, IList<JsStatement> currentBlock, bool isFirstStatement) {
			if (_isIteratorBlock && (FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement, InterestingConstruct.YieldReturn) || (stmt.Finally != null && stmt.Catch == null && !currentState.FinallyStack.IsEmpty))) {
				if (stmt.Catch != null)
					throw new InvalidOperationException("Cannot yield return from try with catch");
				string handlerName = _allocateFinallyHandler();
				JsBlockStatement handler;
				if (FindInterestingConstructsVisitor.Analyze(stmt.Finally, InterestingConstruct.Label)) {
					var inner = ProcessInner(stmt.Finally, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue);
					handler = new JsBlockStatement(new[]  { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1));
					handler = new FinalizerRewriter(_stateVariableName, _labelStates).Process(handler);
				}
				else {
					handler = stmt.Finally;
				}

				_finallyHandlers.Add(Tuple.Create(handlerName, handler));
				var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState);
				var innerState = CreateNewStateValue(currentState.FinallyStack, handlerName);
				var stateBeforeFinally = CreateNewStateValue(innerState.FinallyStack);
				currentBlock.Add(new JsSetNextStateStatement(innerState.StateValue));
				currentBlock.AddRange(Handle(ImmutableStack<StackEntry>.Empty.Push(new StackEntry(stmt.GuardedStatement, 0)), breakStack, continueStack, new State(currentState.LoopLabelName, currentState.StateValue, innerState.FinallyStack), stateBeforeFinally, false, false));

				Enqueue(ImmutableStack<StackEntry>.Empty.Push(new StackEntry(new JsBlockStatement(new JsBlockStatement(new JsStatement[0], true)), 0)), breakStack, continueStack, stateBeforeFinally, stateAfter.Item1);
				if (!stack.IsEmpty || location.Index < location.Block.Statements.Count - 1) {
					Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState);
				}
				return false;
			}
			else if (_isIteratorBlock && stmt.Finally != null && !currentState.FinallyStack.IsEmpty) {
				// This is necessary to special-case in order to ensure that the inner finally block is executed before all outer ones.
				return HandleTryStatement(new JsTryStatement(new JsTryStatement(stmt.GuardedStatement, stmt.Catch, null), null, stmt.Finally), location, stack, breakStack, continueStack, currentState, returnState, currentBlock, isFirstStatement);
			}
			else {
				var rewriter = new NestedStatementFixer(breakStack, continueStack, currentState, _exitState.Value, _makeSetResult);
				JsBlockStatement guarded;
				var guardedConstructs = FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement);
				if ((guardedConstructs & (InterestingConstruct.Label | InterestingConstruct.Await)) != InterestingConstruct.None) {
					if (!isFirstStatement) {
						var sv = CreateNewStateValue(currentState.FinallyStack);
						Enqueue(stack.Push(location), breakStack, continueStack, sv, returnState);
						currentBlock.Add(new JsGotoStateStatement(sv, currentState));
						return false;
					}

					var inner  = ProcessInner(stmt.GuardedStatement, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue);
					guarded    = new JsBlockStatement(inner.Item1);
					currentBlock.Add(new JsSetNextStateStatement(inner.Item2));
				}
				else {
					guarded = rewriter.Process(stmt.GuardedStatement);
				}

				JsCatchClause @catch;
				if (stmt.Catch != null) {
					if (FindInterestingConstructsVisitor.Analyze(stmt.Catch.Body, InterestingConstruct.Label)) {
						var inner = ProcessInner(stmt.Catch.Body, breakStack, continueStack, currentState.FinallyStack, null);
						@catch = new JsCatchClause(stmt.Catch.Identifier, new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1)));
					}
					else {
						var body = rewriter.Process(stmt.Catch.Body);
						@catch = ReferenceEquals(body, stmt.Catch.Body) ? stmt.Catch : new JsCatchClause(stmt.Catch.Identifier, body);
					}
				}
				else
					@catch = null;

				JsBlockStatement @finally;
				if (stmt.Finally != null) {
					if (FindInterestingConstructsVisitor.Analyze(stmt.Finally, InterestingConstruct.Label)) {
						var inner = ProcessInner(stmt.Finally, breakStack, continueStack, currentState.FinallyStack, null);
						@finally = new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1));
					}
					else
						@finally = rewriter.Process(stmt.Finally);

					if ((guardedConstructs & InterestingConstruct.Await) != InterestingConstruct.None) {
						// Wrap the finally block inside an 'if (doFinallyBlocks) {}'
						@finally = new JsBlockStatement(new JsIfStatement(JsExpression.Identifier(_doFinallyBlocksVariableName), @finally, null));
					}
				}
				else
					@finally = null;

				if (currentBlock.Count > 0 && _childStates.ContainsKey(currentState.StateValue)) {
					var newBlock = new JsIfStatement(JsExpression.Same(JsExpression.Identifier(_stateVariableName), JsExpression.Number(currentState.StateValue)), new JsBlockStatement(currentBlock), null);
					currentBlock.Clear();
					currentBlock.Add(newBlock);
				}

				currentBlock.Add(new JsTryStatement(guarded, @catch, @finally));
				return true;
			}
		}
예제 #15
0
 public void Visit(JsIfStatement node)
 {
     BeforeVisit(node);
     DefaultVisit(node, VisitIfStatement);
     AfterVisit(node);
 }
예제 #16
0
 public virtual void VisitIfStatement(JsIfStatement node)
 {
 }