private Node GenExprTransformHelper(GeneratorExpression node) { decompiler.AddToken(Token.LP); int lineno = node.GetLineno(); Node expr = Transform(node.GetResult()); IList<GeneratorExpressionLoop> loops = node.GetLoops(); int numLoops = loops.Count; // Walk through loops, collecting and defining their iterator symbols. Node[] iterators = new Node[numLoops]; Node[] iteratedObjs = new Node[numLoops]; for (int i = 0; i < numLoops; i++) { GeneratorExpressionLoop acl = loops[i]; decompiler.AddName(" "); decompiler.AddToken(Token.FOR); decompiler.AddToken(Token.LP); AstNode iter = acl.GetIterator(); string name = null; if (iter.GetType() == Token.NAME) { name = iter.GetString(); decompiler.AddName(name); } else { // destructuring assignment Decompile(iter); name = currentScriptOrFn.GetNextTempName(); DefineSymbol(Token.LP, name, false); expr = CreateBinary(Token.COMMA, CreateAssignment(Token.ASSIGN, iter, CreateName(name)), expr); } Node init = CreateName(name); // Define as a let since we want the scope of the variable to // be restricted to the array comprehension DefineSymbol(Token.LET, name, false); iterators[i] = init; decompiler.AddToken(Token.IN); iteratedObjs[i] = Transform(acl.GetIteratedObject()); decompiler.AddToken(Token.RP); } // generate code for tmpArray.push(body) Node yield = new Node(Token.YIELD, expr, node.GetLineno()); Node body = new Node(Token.EXPR_VOID, yield, lineno); if (node.GetFilter() != null) { decompiler.AddName(" "); decompiler.AddToken(Token.IF); decompiler.AddToken(Token.LP); body = CreateIf(Transform(node.GetFilter()), body, null, lineno); decompiler.AddToken(Token.RP); } // Now walk loops in reverse to build up the body statement. int pushed = 0; try { for (int i_1 = numLoops - 1; i_1 >= 0; i_1--) { GeneratorExpressionLoop acl = loops[i_1]; Scope loop = CreateLoopNode(null, acl.GetLineno()); // no label PushScope(loop); pushed++; body = CreateForIn(Token.LET, loop, iterators[i_1], iteratedObjs[i_1], body, acl.IsForEach()); } } finally { for (int i_1 = 0; i_1 < pushed; i_1++) { PopScope(); } } decompiler.AddToken(Token.RP); return body; }
private Node TransformGenExpr(GeneratorExpression node) { Node pn; FunctionNode fn = new FunctionNode(); fn.SetSourceName(currentScriptOrFn.GetNextTempName()); fn.SetIsGenerator(); fn.SetFunctionType(FunctionNode.FUNCTION_EXPRESSION); fn.SetRequiresActivation(); int functionType = fn.GetFunctionType(); int start = decompiler.MarkFunctionStart(functionType); Node mexpr = DecompileFunctionHeader(fn); int index = currentScriptOrFn.AddFunction(fn); Parser.PerFunctionVariables savedVars = new Parser.PerFunctionVariables(this, fn); try { // If we start needing to record much more codegen metadata during // function parsing, we should lump it all into a helper class. Node destructuring = (Node)fn.GetProp(Node.DESTRUCTURING_PARAMS); fn.RemoveProp(Node.DESTRUCTURING_PARAMS); int lineno = node.lineno; ++nestingOfFunction; // only for body, not params Node body = GenExprTransformHelper(node); if (!fn.IsExpressionClosure()) { decompiler.AddToken(Token.RC); } fn.SetEncodedSourceBounds(start, decompiler.MarkFunctionEnd(start)); if (functionType != FunctionNode.FUNCTION_EXPRESSION && !fn.IsExpressionClosure()) { // Add EOL only if function is not part of expression // since it gets SEMI + EOL from Statement in that case decompiler.AddToken(Token.EOL); } if (destructuring != null) { body.AddChildToFront(new Node(Token.EXPR_VOID, destructuring, lineno)); } int syntheticType = fn.GetFunctionType(); pn = InitFunction(fn, index, body, syntheticType); if (mexpr != null) { pn = CreateAssignment(Token.ASSIGN, mexpr, pn); if (syntheticType != FunctionNode.FUNCTION_EXPRESSION) { pn = CreateExprStatementNoReturn(pn, fn.GetLineno()); } } } finally { --nestingOfFunction; savedVars.Restore(); } Node call = CreateCallOrNew(Token.CALL, pn); call.SetLineno(node.GetLineno()); decompiler.AddToken(Token.LP); decompiler.AddToken(Token.RP); return call; }