/// <summary> /// Determine whether it matters if an expression is run before or after another sequence of statements/expressions /// </summary> public static bool DoesOrderMatter(JsExpression expr1, ExpressionCompileResult expr2) { // The algorithm is rather simple and conservative: For the both expression (sequences), determine a) which locals are read, b) which locals are written, and c) whether can possibly read or write any external state. // The order of the two expressions then matters if and only if: // 1) Either expression writes a local that the other uses, // 2) The expressions write to the same locals, or // 3) Both the expressions use any external state. var v1 = new FindObservableStateVisitor(); v1.VisitExpression(expr1, null); var v2 = new FindObservableStateVisitor(); foreach (var s in expr2.AdditionalStatements) { v2.VisitStatement(s, null); } v2.VisitExpression(expr2.Expression, null); if (v1.Result.LocalReadSet.Overlaps(v2.Result.LocalWriteSet) || v1.Result.LocalWriteSet.Overlaps(v2.Result.LocalReadSet)) { return(true); } if (v1.Result.LocalWriteSet.Overlaps(v2.Result.LocalWriteSet)) { return(true); } if (v1.Result.UsesExternalState && v2.Result.UsesExternalState) { return(true); } return(false); }
public static void CreateTemporariesForAllExpressionsThatHaveToBeEvaluatedBeforeNewExpression(IList<JsStatement> statementList, IList<JsExpression> expressions, ExpressionCompileResult newExpressions, Func<string> createTemporaryVariable) { for (int i = 0; i < expressions.Count; i++) { if (ExpressionOrderer.DoesOrderMatter(expressions[i], newExpressions)) { var temp = createTemporaryVariable(); statementList.Add(new JsVariableDeclarationStatement(temp, expressions[i])); expressions[i] = JsExpression.Identifier(temp); } } }