public void VisitNode(JSWhileLoop wl) { CheckLabel(wl); BlockStack.Push(new EnclosingBlockEntry { Block = wl, ParentNode = ParentNode, Depth = BlockStack.Count }); try { VisitChildren(wl); } finally { BlockStack.Pop(); } }
public void VisitNode(JSWhileLoop wl) { var condInvocation = wl.Condition as JSInvocationExpression; JSVariable enumeratorVariable; if ( (condInvocation != null) && (condInvocation.JSMethod != null) && (condInvocation.JSMethod.Identifier == "MoveNext") && (condInvocation.JSMethod.Method.DeclaringType.Interfaces.Any((ii) => ii.Item1.FullName == "System.Collections.IEnumerator")) && ((enumeratorVariable = condInvocation.ThisReference as JSVariable) != null) ) { var enumeratorType = condInvocation.JSMethod.Method.DeclaringType; while (EnableEnumeratorRemoval) { var enumeratorAssignmentBeforeLoop = ( from boe in SeenAssignments let boeLeftVar = (boe.Left as JSVariable) where (boeLeftVar != null) && (boeLeftVar.Name == enumeratorVariable.Name) select boe ).LastOrDefault(); if (enumeratorAssignmentBeforeLoop == null) break; var enumeratorValue = enumeratorAssignmentBeforeLoop.Right; var assignmentInvocation = enumeratorValue as JSInvocationExpression; if (assignmentInvocation == null) { var rre = enumeratorValue as JSResultReferenceExpression; if (rre != null) assignmentInvocation = rre.Referent as JSInvocationExpression; } if (assignmentInvocation == null) break; var jsm = assignmentInvocation.JSMethod; if (jsm == null) break; var attrParams2 = jsm.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSUnderlyingArray"); if (attrParams2 != null) { var arrayMember = (string)attrParams2[0].Value; var lengthMember = (string)attrParams2[1].Value; var replacement = ReplaceWhileLoopAndEnumerator( wl, assignmentInvocation.ThisReference, condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType, arrayMember, lengthMember ); ParentNode.ReplaceChild(wl, replacement); EnumeratorsToKill.Add(enumeratorVariable); VisitReplacement(replacement); return; } break; } var attrParams = enumeratorType.Metadata.GetAttributeParameters("JSIL.Meta.JSIsArrayEnumerator"); if (attrParams != null) { var arrayMember = (string)attrParams[0].Value; var indexMember = (string)attrParams[1].Value; var lengthMember = (string)attrParams[2].Value; var replacement = ReplaceWhileLoop( wl, condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType, arrayMember, indexMember, lengthMember ); ParentNode.ReplaceChild(wl, replacement); VisitReplacement(replacement); return; } } VisitChildren(wl); }
private JSForLoop ReplaceWhileLoopAndEnumerator(JSWhileLoop wl, JSExpression backingStore, JSExpression enumerator, TypeInfo enumeratorType, string arrayMember, string lengthMember) { var loopId = _NextLoopId++; var arrayVariableName = String.Format("a${0:x}", loopId); var indexVariableName = String.Format("i${0:x}", loopId); var lengthVariableName = String.Format("l${0:x}", loopId); var currentPropertyReference = enumeratorType.Definition.Properties.First((p) => p.Name == "Current"); var currentPropertyInfo = enumeratorType.Source.GetProperty(currentPropertyReference); var itemType = currentPropertyInfo.ReturnType; var arrayType = new ArrayType(itemType); var arrayVariable = new JSVariable( arrayVariableName, arrayType, Function.Method.Reference, JSDotExpression.New(backingStore, new JSStringIdentifier(arrayMember, arrayType)) ); var indexVariable = new JSVariable( indexVariableName, TypeSystem.Int32, Function.Method.Reference, JSLiteral.New(0) ); var lengthVariable = new JSVariable( lengthVariableName, TypeSystem.Int32, Function.Method.Reference, JSDotExpression.New(backingStore, new JSStringIdentifier(lengthMember, TypeSystem.Int32)) ); var initializer = new JSVariableDeclarationStatement( new JSBinaryOperatorExpression( JSOperator.Assignment, arrayVariable, arrayVariable.DefaultValue, arrayVariable.IdentifierType ), new JSBinaryOperatorExpression( JSOperator.Assignment, indexVariable, indexVariable.DefaultValue, indexVariable.IdentifierType ), new JSBinaryOperatorExpression( JSOperator.Assignment, lengthVariable, lengthVariable.DefaultValue, lengthVariable.IdentifierType ) ); var condition = new JSBinaryOperatorExpression( JSBinaryOperator.LessThan, indexVariable, lengthVariable, TypeSystem.Boolean ); var increment = new JSUnaryOperatorExpression( JSUnaryOperator.PostIncrement, indexVariable, TypeSystem.Int32 ); var result = new JSForLoop( initializer, condition, new JSExpressionStatement(increment), wl.Statements.ToArray() ); result.Index = wl.Index; new PropertyAccessReplacer( enumerator, new JSProperty(currentPropertyReference, currentPropertyInfo), new JSIndexerExpression( arrayVariable, indexVariable, itemType ) ).Visit(result); return result; }
public JSWhileLoop TranslateNode(ILWhileLoop loop) { JSExpression condition; if (loop.Condition != null) condition = TranslateNode(loop.Condition); else condition = JSLiteral.New(true); var result = new JSWhileLoop(condition); result.Label = String.Format("__loop{0}__", UnlabelledBlockCount++); Blocks.Push(result); var body = TranslateNode(loop.BodyBlock); Blocks.Pop(); result.Statements.Add(body); return result; }
public void VisitNode(JSWhileLoop whileLoop) { JSVariable initVariable = null, lastVariable = null; JSBinaryOperator initOperator = null; JSExpression initValue = null; var prevEStmt = PreviousSibling as JSExpressionStatement; var prevVDS = PreviousSibling as JSVariableDeclarationStatement; if (prevEStmt != null) { var boe = prevEStmt.Expression as JSBinaryOperatorExpression; if ( (boe != null) && (boe.Operator is JSAssignmentOperator) && (boe.Left is JSVariable) ) { initVariable = (JSVariable)boe.Left; initOperator = boe.Operator; initValue = boe.Right; } } else if (prevVDS != null) { var decl = prevVDS.Declarations.FirstOrDefault( (d) => !d.IsNull ); if (decl != null) { initVariable = (JSVariable)decl.Left; initOperator = decl.Operator; initValue = decl.Right; } } var lastStatement = whileLoop.Statements.LastOrDefault(); while ((lastStatement != null) && (lastStatement.GetType() == typeof(JSBlockStatement))) lastStatement = ((JSBlockStatement)lastStatement).Statements.LastOrDefault(); var lastExpressionStatement = lastStatement as JSExpressionStatement; if (lastExpressionStatement != null) { var lastUoe = lastExpressionStatement.Expression as JSUnaryOperatorExpression; var lastBoe = lastExpressionStatement.Expression as JSBinaryOperatorExpression; if ((lastUoe != null) && (lastUoe.Operator is JSUnaryMutationOperator)) { lastVariable = lastUoe.Expression as JSVariable; } else if ((lastBoe != null) && (lastBoe.Operator is JSAssignmentOperator)) { lastVariable = lastBoe.Left as JSVariable; if ( (lastVariable != null) && !lastBoe.Right.AllChildrenRecursive.Any( (n) => lastVariable.Equals(n) ) ) { lastVariable = null; } } } var lastIfStatement = lastStatement as JSIfStatement; if ( (lastIfStatement != null) && whileLoop.Condition is JSBooleanLiteral && ((JSBooleanLiteral)whileLoop.Condition).Value ) { var innerStatement = lastIfStatement.TrueClause; while (innerStatement is JSBlockStatement) { var bs = (JSBlockStatement)innerStatement; if (bs.Statements.Count != 1) { innerStatement = null; break; } innerStatement = bs.Statements[0]; } var eStmt = innerStatement as JSExpressionStatement; if (eStmt != null) { var breakExpr = eStmt.Expression as JSBreakExpression; if ((breakExpr != null) && (breakExpr.TargetLabel == whileLoop.Label)) { whileLoop.ReplaceChildRecursive(lastIfStatement, new JSNullStatement()); var doLoop = new JSDoLoop( new JSUnaryOperatorExpression(JSOperator.LogicalNot, lastIfStatement.Condition), whileLoop.Statements.ToArray() ); doLoop.Label = whileLoop.Label; ParentNode.ReplaceChild(whileLoop, doLoop); VisitChildren(doLoop); return; } } } bool cantBeFor = false; if ((initVariable != null) && (lastVariable != null) && !initVariable.Equals(lastVariable) ) { cantBeFor = true; } else if ((initVariable ?? lastVariable) == null) { cantBeFor = true; } else if (!whileLoop.Condition.AllChildrenRecursive.Any( (n) => (initVariable ?? lastVariable).Equals(n) )) { cantBeFor = true; } if (!cantBeFor) { JSStatement initializer = null, increment = null; if (initVariable != null) { initializer = PreviousSibling as JSStatement; ParentNode.ReplaceChild(PreviousSibling, new JSNullStatement()); } if (lastVariable != null) { increment = lastExpressionStatement; whileLoop.ReplaceChildRecursive(lastExpressionStatement, new JSNullStatement()); } var forLoop = new JSForLoop( initializer, whileLoop.Condition, increment, whileLoop.Statements.ToArray() ); forLoop.Label = whileLoop.Label; ParentNode.ReplaceChild(whileLoop, forLoop); VisitChildren(forLoop); } else { VisitChildren(whileLoop); } }
public void VisitNode(JSWhileLoop wl) { var condInvocation = wl.Condition as JSInvocationExpression; JSVariable enumeratorVariable; if ( (condInvocation != null) && (condInvocation.JSMethod != null) && (condInvocation.JSMethod.Identifier == "MoveNext") && (condInvocation.JSMethod.Method.DeclaringType.Interfaces.Any((ii) => ii.Item1.FullName == "System.Collections.IEnumerator")) && ((enumeratorVariable = condInvocation.ThisReference as JSVariable) != null) ) { var enumeratorType = condInvocation.JSMethod.Method.DeclaringType; while (EnableEnumeratorRemoval) { var firstPass = FunctionSource.GetFirstPass(Function.Method.QualifiedIdentifier); if (firstPass == null) break; var enumeratorAssignments = (from a in firstPass.Assignments where a.Target.Name == enumeratorVariable.Name select a).ToArray(); if (enumeratorAssignments.Length != 1) break; var enumeratorValue = enumeratorAssignments[0].NewValue; var assignmentInvocation = enumeratorValue as JSInvocationExpression; if (assignmentInvocation == null) { var rre = enumeratorValue as JSResultReferenceExpression; if (rre != null) assignmentInvocation = rre.Referent as JSInvocationExpression; } if (assignmentInvocation == null) break; var jsm = assignmentInvocation.JSMethod; if (jsm == null) break; var attrParams2 = jsm.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSUnderlyingArray"); if (attrParams2 != null) { var arrayMember = (string)attrParams2[0].Value; var lengthMember = (string)attrParams2[1].Value; var replacement = ReplaceWhileLoopAndEnumerator( wl, assignmentInvocation.ThisReference, condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType, arrayMember, lengthMember ); ParentNode.ReplaceChild(wl, replacement); new VariableEliminator(enumeratorVariable, new JSNullExpression()).Visit(Function); VisitReplacement(replacement); } break; } var attrParams = enumeratorType.Metadata.GetAttributeParameters("JSIL.Meta.JSIsArrayEnumerator"); if (attrParams != null) { var arrayMember = (string)attrParams[0].Value; var indexMember = (string)attrParams[1].Value; var lengthMember = (string)attrParams[2].Value; var replacement = ReplaceWhileLoop( wl, condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType, arrayMember, indexMember, lengthMember ); ParentNode.ReplaceChild(wl, replacement); VisitReplacement(replacement); return; } } VisitChildren(wl); }