internal override MSAst.Expression Transform(AstGenerator ag) { if (ag.IsGenerator) { if (_expression != null) { // Statements can't return null, so return a rethrow. // Callers should detecet the ag.AddError and avoid trying to execute the tree, // but if they accidentally do, use Throw instead of empty so that // we'll get an exception. return Ast.Throw( Ast.New( typeof(InvalidOperationException).GetConstructor(Type.EmptyTypes) ) ); } return ag.AddDebugInfo(AstUtils.YieldBreak(ag.GeneratorLabel), Span); } return ag.AddDebugInfo( Ast.Return( ag.ReturnLabel, ag.TransformOrConstantNull(_expression, typeof(object)) ), Span ); }
internal override MSAst.Expression Transform(AstGenerator ag) { List<MSAst.Expression> statements = new List<MSAst.Expression>(); for (int i = 0; i < _names.Length; i++) { statements.Add( // _references[i] = PythonOps.Import(<code context>, _names[i]) ag.AddDebugInfo( AstUtils.Assign( _variables[i].Variable, Ast.Call( AstGenerator.GetHelperMethod( // helper _asNames[i] == SymbolId.Empty ? "ImportTop" : "ImportBottom" ), AstUtils.CodeContext(), // 1st arg - code context Ast.Constant(_names[i].MakeString()), // 2nd arg - module name Ast.Constant(_forceAbsolute ? 0 : -1) // 3rd arg - absolute or relative imports ) ), _names[i].Span ) ); } statements.Add(Ast.Empty()); return ag.AddDebugInfo(Ast.Block(statements.ToArray()), Span); }
internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, Operators op) { if (op == Operators.None) { return ag.AddDebugInfoAndVoid( Binders.Set( ag.BinderState, typeof(object), SymbolTable.IdToString(_name), ag.Transform(_target), right ), span ); } else { MSAst.ParameterExpression temp = ag.GetTemporary("inplace"); return ag.AddDebugInfo( Ast.Block( Ast.Assign(temp, ag.Transform(_target)), SetMemberOperator(ag, right, op, temp), Ast.Empty() ), Span.Start, span.End ); } }
internal override MSAst.Expression Transform(AstGenerator ag) { ReadOnlyCollectionBuilder<MSAst.Expression> statements = new ReadOnlyCollectionBuilder<MSAst.Expression>(); for (int i = 0; i < _names.Length; i++) { statements.Add( // _references[i] = PythonOps.Import(<code context>, _names[i]) ag.AddDebugInfoAndVoid( GlobalAllocator.Assign( ag.Globals.GetVariable(ag, _variables[i]), Ast.Call( AstGenerator.GetHelperMethod( // helper _asNames[i] == null ? "ImportTop" : "ImportBottom" ), ag.LocalContext, // 1st arg - code context AstUtils.Constant(_names[i].MakeString()), // 2nd arg - module name AstUtils.Constant(_forceAbsolute ? 0 : -1) // 3rd arg - absolute or relative imports ) ), _names[i].Span ) ); } statements.Add(AstUtils.Empty()); return ag.AddDebugInfo(Ast.Block(statements.ToReadOnlyCollection()), Span); }
internal override MSAst.Expression Transform(AstGenerator ag) { if (ag.InLoop) { return ag.AddDebugInfo(MSAst.Expression.Break(ag.BreakLabel), Span); } else { return null; } }
internal override MSAst.Expression Transform(AstGenerator ag, Type type) { MSAst.ParameterExpression list = ag.GetTemporary("list_comprehension_list", typeof(List)); // 1. Initialization code - create list and store it in the temp variable MSAst.Expression initialize = Ast.Assign( list, Ast.Call( AstGenerator.GetHelperMethod("MakeList", Type.EmptyTypes) // method ) ); // 2. Create body from _item: list.Append(_item) MSAst.Expression body = ag.AddDebugInfo( Ast.Call( AstGenerator.GetHelperMethod("ListAddForComprehension"), list, ag.TransformAsObject(_item) ), _item.Span ); // 3. Transform all iterators in reverse order, building the true body: int current = _iterators.Length; while (current-- > 0) { ListComprehensionIterator iterator = _iterators[current]; body = iterator.Transform(ag, body); } return Ast.Block( initialize, body, list // result ); }
internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.Expression raiseExpression; if (_type == null && _value == null && _traceback == null) { raiseExpression = Ast.Call( AstGenerator.GetHelperMethod("MakeRethrownException"), ag.LocalContext ); if (!ag._isEmittingFinally) { raiseExpression = Ast.Block( ag.UpdateLineUpdated(true), raiseExpression ); } } else { raiseExpression = Ast.Call( AstGenerator.GetHelperMethod("MakeException"), ag.LocalContext, ag.TransformOrConstantNull(_type, typeof(object)), ag.TransformOrConstantNull(_value, typeof(object)), ag.TransformOrConstantNull(_traceback, typeof(object)) ); } return ag.AddDebugInfo( Ast.Throw(raiseExpression), Span ); }
internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.MethodCallExpression call; if (_locals == null && _globals == null) { // exec code call = Ast.Call( AstGenerator.GetHelperMethod("UnqualifiedExec"), AstUtils.CodeContext(), ag.TransformAsObject(_code) ); } else { // exec code in globals [ , locals ] // We must have globals now (locals is last and may be absent) Debug.Assert(_globals != null); call = Ast.Call( AstGenerator.GetHelperMethod("QualifiedExec"), AstUtils.CodeContext(), ag.TransformAsObject(_code), ag.TransformAndDynamicConvert(_globals, typeof(IAttributesCollection)), ag.TransformOrConstantNull(_locals, typeof(object)) ); } return ag.AddDebugInfo(call, Span); }
internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.Expression result; if (_else != null) { result = ag.Transform(_else); } else { result = Ast.Empty(); } // Now build from the inside out int i = _tests.Length; while (i-- > 0) { IfStatementTest ist = _tests[i]; result = ag.AddDebugInfo( Ast.Condition( ag.TransformAndDynamicConvert(ist.Test, typeof(bool)), ag.Transform(ist.Body), result ), new SourceSpan(ist.Start, ist.Header) ); } return result; }
internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.Expression destination = ag.TransformAsObject(_dest); if (_expressions.Length == 0) { MSAst.Expression result; if (destination != null) { result = Ast.Call( AstGenerator.GetHelperMethod("PrintNewlineWithDest"), ag.LocalContext, destination ); } else { result = Ast.Call( AstGenerator.GetHelperMethod("PrintNewline"), ag.LocalContext ); } return ag.AddDebugInfo(result, Span); } else { // Create list for the individual statements List<MSAst.Expression> statements = new List<MSAst.Expression>(); // Store destination in a temp, if we have one if (destination != null) { MSAst.ParameterExpression temp = ag.GetTemporary("destination"); statements.Add( ag.MakeAssignment(temp, destination) ); destination = temp; } for (int i = 0; i < _expressions.Length; i++) { string method = (i < _expressions.Length - 1 || _trailingComma) ? "PrintComma" : "Print"; Expression current = _expressions[i]; MSAst.MethodCallExpression mce; if (destination != null) { mce = Ast.Call( AstGenerator.GetHelperMethod(method + "WithDest"), ag.LocalContext, destination, ag.TransformAsObject(current) ); } else { mce = Ast.Call( AstGenerator.GetHelperMethod(method), ag.LocalContext, ag.TransformAsObject(current) ); } statements.Add(mce); } statements.Add(AstUtils.Empty()); return ag.AddDebugInfo(Ast.Block(statements.ToArray()), Span); } }
internal override MSAst.Expression Transform(AstGenerator ag) { // Transform to series of individual del statements. ReadOnlyCollectionBuilder<MSAst.Expression> statements = new ReadOnlyCollectionBuilder<MSAst.Expression>(_expressions.Length + 1); for (int i = 0; i < _expressions.Length; i++) { statements.Add(_expressions[i].TransformDelete(ag)); } statements.Add(AstUtils.Empty()); return ag.AddDebugInfo(MSAst.Expression.Block(statements), Span); }
internal override MSAst.Expression Transform(AstGenerator ag) { if (ag.InFinally) { return null; } else if (ag.InLoop) { return ag.AddDebugInfo(MSAst.Expression.Continue(ag.ContinueLabel), Span); } else { return null; } }
internal override MSAst.Expression Transform(AstGenerator ag) { // Transform to series of individual del statements. MSAst.Expression[] statements = new MSAst.Expression[_expressions.Length + 1]; for (int i = 0; i < _expressions.Length; i++) { statements[i] = _expressions[i].TransformDelete(ag); } statements[_expressions.Length] = AstUtils.Empty(); return ag.AddDebugInfo(MSAst.Expression.Block(statements), Span); }
internal override MSAst.Expression Transform(AstGenerator ag) { if (ag.InFinally) { ag.AddError("'continue' not supported inside 'finally' clause", Span); return null; } else if (ag.InLoop) { return ag.AddDebugInfo(MSAst.Expression.Continue(ag.ContinueLabel), Span); } else { ag.AddError("'continue' not properly in loop", Span); return null; } }
internal override MSAst.Expression Transform(AstGenerator ag) { // Transform to series of individual del statements. MSAst.Expression[] statements = new MSAst.Expression[_expressions.Length + 1]; for (int i = 0; i < _expressions.Length; i++) { statements[i] = _expressions[i].TransformDelete(ag); if (statements[i] == null) { throw PythonOps.SyntaxError(string.Format("can't delete {0}", _expressions[i].NodeName), ag.Context.SourceUnit, _expressions[i].Span, 1); } } statements[_expressions.Length] = MSAst.Expression.Empty(); return ag.AddDebugInfo(MSAst.Expression.Block(statements), Span); }
internal override MSAst.Expression Transform(AstGenerator ag) { // If debugging is off, return empty statement if (ag.Optimize) { return ag.AddDebugInfo(AstUtils.Empty(), Span); } // Transform into: // if (_test) { // } else { // RaiseAssertionError(_message); // } return ag.AddDebugInfo( AstUtils.Unless( // if ag.TransformAndDynamicConvert(_test, typeof(bool)), // _test Ast.Call( // else branch AstGenerator.GetHelperMethod("RaiseAssertionError"), ag.TransformOrConstantNull(_message, typeof(object)) ) ), Span ); }
internal override MSAst.Expression Transform(AstGenerator ag) { // Only the body is "in the loop" for the purposes of break/continue // The "else" clause is outside MSAst.LabelTarget breakLabel, continueLabel; MSAst.Expression body = ag.TransformLoopBody(_body, out breakLabel, out continueLabel); return AstUtils.While( ag.AddDebugInfo( ag.TransformAndDynamicConvert(_test, typeof(bool)), Header ), body, ag.Transform(_else), breakLabel, continueLabel ); }
internal override MSAst.Expression Transform(AstGenerator ag) { // Only the body is "in the loop" for the purposes of break/continue // The "else" clause is outside MSAst.LabelTarget breakLabel, continueLabel; ConstantExpression constTest = _test as ConstantExpression; if (constTest != null && constTest.Value is int) { // while 0: / while 1: int val = (int)constTest.Value; if (val == 0) { // completely optimize the loop away if (_else == null) { return MSAst.Expression.Empty(); } else { return ag.Transform(_else); } } MSAst.Expression test = MSAst.Expression.Constant(true); MSAst.Expression res = AstUtils.While( test, ag.TransformLoopBody(_body, SourceLocation.Invalid, out breakLabel, out continueLabel), ag.Transform(_else), breakLabel, continueLabel ); if (_test.Start.Line != _body.Start.Line) { res = ag.AddDebugInfo(res, _test.Span); } return res; } return AstUtils.While( ag.AddDebugInfo( ag.TransformAndDynamicConvert(_test, typeof(bool)), Header ), ag.TransformLoopBody(_body, _test.Start, out breakLabel, out continueLabel), ag.Transform(_else), breakLabel, continueLabel ); }
internal override MSAst.Expression Transform(AstGenerator ag, Type type) { // (yield z) becomes: // .comma (1) { // .void ( .yield_statement (_expression) ), // $gen.CheckThrowable() // <-- has return result from send // } return Ast.Block( ag.AddDebugInfo( AstUtils.YieldReturn( ag.GeneratorLabel, AstUtils.Convert(ag.Transform(_expression), typeof(object)) ), Span ), CreateCheckThrowExpression(ag, Span) // emits ($gen.CheckThrowable()) ); }
internal override MSAst.Expression Transform(AstGenerator ag) { MSAst.MethodCallExpression raiseExpression; if (_type == null && _value == null && _traceback == null) { raiseExpression = Ast.Call( AstGenerator.GetHelperMethod("MakeRethrownException"), AstUtils.CodeContext() ); } else { raiseExpression = Ast.Call( AstGenerator.GetHelperMethod("MakeException"), AstUtils.CodeContext(), ag.TransformOrConstantNull(_type, typeof(object)), ag.TransformOrConstantNull(_value, typeof(object)), ag.TransformOrConstantNull(_traceback, typeof(object)) ); } return ag.AddDebugInfo( Ast.Throw(raiseExpression), Span ); }
internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, PythonOperationKind op) { if (op == PythonOperationKind.None) { return ag.AddDebugInfoAndVoid( ag.Set( typeof(object), _name, ag.Transform(_target), right ), span ); } else { MSAst.ParameterExpression temp = ag.GetTemporary("inplace"); return ag.AddDebugInfo( Ast.Block( Ast.Assign(temp, ag.Transform(_target)), SetMemberOperator(ag, right, op, temp), AstUtils.Empty() ), Span.Start, span.End ); } }
/// <summary> /// Surrounds the body of an except block w/ the appropriate code for maintaining the traceback. /// </summary> private static MSAst.Expression GetTracebackHeader(SourceSpan span, AstGenerator ag, MSAst.ParameterExpression exception, MSAst.Expression body) { // we are about to enter a except block. We need to emit the line number update so we track // the line that the exception was thrown from. We then need to build exc_info() so that // it's available. Finally we clear the list of dynamic stack frames because they've all // been associated with this exception. return ag.AddDebugInfo( Ast.Block( // pass false so if we take another exception we'll add it to the frame list ag.TrackLines ? ag.GetLineNumberUpdateExpression(false) : MSAst.Expression.Empty(), Ast.Call( AstGenerator.GetHelperMethod("BuildExceptionInfo"), AstUtils.CodeContext(), exception ), body, Ast.Empty() ), span ); }
internal override MSAst.Expression Transform(AstGenerator ag) { Debug.Assert(_variable != null, "Shouldn't be called by lamda expression"); ag.DisableInterpreter = true; MSAst.Expression function = TransformToFunctionExpression(ag); return ag.AddDebugInfo(AstUtils.Assign(_variable.Variable, function), new SourceSpan(Start, Header)); }
internal static MSAst.Expression TransformForStatement(AstGenerator ag, MSAst.ParameterExpression enumerator, Expression list, Expression left, MSAst.Expression body, Statement else_, SourceSpan span, SourceLocation header, MSAst.LabelTarget breakLabel, MSAst.LabelTarget continueLabel) { // enumerator = PythonOps.GetEnumeratorForIteration(list) MSAst.Expression init = Ast.Assign( enumerator, ag.Operation( typeof(IEnumerator), PythonOperationKind.GetEnumeratorForIteration, ag.TransformAsObject(list) ) ); // while enumerator.MoveNext(): // left = enumerator.Current // body // else: // else MSAst.Expression ls = AstUtils.Loop( ag.AddDebugInfo(Ast.Call( enumerator, typeof(IEnumerator).GetMethod("MoveNext") ), left.Span), null, Ast.Block( left.TransformSet( ag, SourceSpan.None, Ast.Call( enumerator, typeof(IEnumerator).GetProperty("Current").GetGetMethod() ), PythonOperationKind.None ), body, ag.UpdateLineNumber(list.Start.Line), AstUtils.Empty() ), ag.Transform(else_), breakLabel, continueLabel ); return Ast.Block( init, ls, AstUtils.Empty() ); }
internal override MSAst.Expression Transform(AstGenerator ag) { // allocated all variables here so they won't be shared w/ other // locals allocated during the body or except blocks. MSAst.ParameterExpression noNestedException = null; if (_finally != null) { noNestedException = ag.GetTemporary("$noException", typeof(bool)); } MSAst.ParameterExpression lineUpdated = null; MSAst.ParameterExpression runElse = null; if (_else != null || (_handlers != null && _handlers.Length > 0)) { lineUpdated = ag.GetTemporary("$lineUpdated", typeof(bool)); if (_else != null) { runElse = ag.GetTemporary("run_else", typeof(bool)); } } // don't allocate locals below here... MSAst.Expression body = ag.Transform(_body); MSAst.Expression @else = ag.Transform(_else); if (body == null) { return null; } MSAst.ParameterExpression exception; MSAst.Expression @catch = TransformHandlers(ag, out exception); MSAst.Expression result; // We have else clause, must generate guard around it if (@else != null) { Debug.Assert(@catch != null); // run_else = true; // try { // try_body // } catch ( ... ) { // run_else = false; // catch_body // } // if (run_else) { // else_body // } result = Ast.Block( Ast.Assign(runElse, Ast.Constant(true)), // save existing line updated, we could choose to do this only for nested exception handlers. ag.PushLineUpdated(false, lineUpdated), AstUtils.Try( ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Span.Start, _header)), body ).Catch(exception, Ast.Assign(runElse, Ast.Constant(false)), @catch, // restore existing line updated after exception handler completes ag.PopLineUpdated(lineUpdated), Ast.Default(body.Type) ), AstUtils.IfThen(runElse, @else ), Ast.Empty() ); } else if (@catch != null) { // no "else" clause // try { // <try body> // } catch (Exception e) { // ... catch handling ... // } // result = AstUtils.Try( ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Span.Start, _header)), // save existing line updated ag.PushLineUpdated(false, lineUpdated), body ).Catch(exception, @catch, // restore existing line updated after exception handler completes ag.PopLineUpdated(lineUpdated), Ast.Default(body.Type) ); } else { result = body; } try { return AddFinally(ag, result, noNestedException); } finally { // free all locals here after the children nodes have been generated if (lineUpdated != null) { ag.FreeTemp(lineUpdated); } if (runElse != null) { ag.FreeTemp(@runElse); } } }
internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) { string name; if (IsLambda) { name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">"; } else { name = SymbolTable.IdToString(_name); } // Create AST generator to generate the body with AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, false); bodyGen.DisableInterpreter = true; // Transform the parameters. // Populate the list of the parameter names and defaults. List<MSAst.Expression> defaults = new List<MSAst.Expression>(0); List<MSAst.Expression> names = new List<MSAst.Expression>(); TransformParameters(ag, bodyGen, defaults, names); List<MSAst.Expression> statements = new List<MSAst.Expression>(); // Create variables and references. Since references refer to // parameters, do this after parameters have been created. CreateVariables(bodyGen, statements); // Initialize parameters - unpack tuples. // Since tuples unpack into locals, this must be done after locals have been created. InitializeParameters(bodyGen, statements); // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close(). // The exception traceback needs to come from the generator's method body, and so we must do the check and throw // from inside the generator. if (IsGenerator) { MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(bodyGen, SourceSpan.None); statements.Add(s1); } MSAst.ParameterExpression extracted = null; if (!IsGenerator && _canSetSysExcInfo) { // need to allocate the exception here so we don't share w/ exceptions made & freed // during the body. extracted = bodyGen.GetTemporary("$ex", typeof(Exception)); } // Transform the body and add the resulting statements into the list TransformBody(bodyGen, statements); if (ag.DebugMode) { // add beginning and ending break points for the function. if (GetExpressionEnd(statements[statements.Count - 1]) != Body.End) { statements.Add(ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Body.End, Body.End))); } } MSAst.Expression body = Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements.ToArray())); // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish. // // Wrap in // $temp = PythonOps.SaveCurrentException() // <body> // PythonOps.RestoreCurrentException($temp) // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class // before it's invoked. This is because the restoration must occur at every place the function returns from // a yield point. That's different than the finally semantics in a generator. if (extracted != null) { MSAst.Expression s = AstUtils.Try( Ast.Assign( extracted, Ast.Call( AstGenerator.GetHelperMethod("SaveCurrentException") ) ), body ).Finally( Ast.Call( AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted ) ); body = s; } body = bodyGen.WrapScopeStatements(body); bodyGen.Block.Body = bodyGen.AddReturnTarget(body); FunctionAttributes flags = ComputeFlags(_parameters); bool needsWrapperMethod = flags != FunctionAttributes.None; if (_canSetSysExcInfo) { flags |= FunctionAttributes.CanSetSysExcInfo; } MSAst.Expression code; if (IsGenerator) { code = bodyGen.Block.MakeGenerator(bodyGen.GeneratorLabel, GetGeneratorDelegateType(_parameters, needsWrapperMethod)); flags |= FunctionAttributes.Generator; } else { code = bodyGen.Block.MakeLambda(GetDelegateType(_parameters, needsWrapperMethod)); } MSAst.Expression ret = Ast.Call( null, // instance typeof(PythonOps).GetMethod("MakeFunction"), // method new ReadOnlyCollection<MSAst.Expression>( new [] { AstUtils.CodeContext(), // 1. Emit CodeContext Ast.Constant(name), // 2. FunctionName code, // 3. delegate names.Count == 0 ? // 4. parameter names Ast.Constant(null, typeof(string[])) : (MSAst.Expression)Ast.NewArrayInit(typeof(string), names), defaults.Count == 0 ? // 5. default values Ast.Constant(null, typeof(object[])) : (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults), Ast.Constant(flags), // 6. flags Ast.Constant(ag.GetDocumentation(_body), typeof(string)), // 7. doc string or null Ast.Constant(this.Start.Line), // 8. line number Ast.Constant(_sourceUnit.Path, typeof(string)) // 9. filename } ) ); ret = ag.AddDecorators(ret, _decorators); return ret; }
internal override MSAst.Expression TransformDelete(AstGenerator ag) { MSAst.Expression[] statements = new MSAst.Expression[_items.Length + 1]; for (int i = 0; i < _items.Length; i++) { statements[i] = _items[i].TransformDelete(ag); } statements[_items.Length] = AstUtils.Empty(); return ag.AddDebugInfo(Ast.Block(statements), Span); }
internal override MSAst.Expression Transform(AstGenerator ag) { if (_names == _star) { // from a[.b] import * return ag.AddDebugInfo( Ast.Call( AstGenerator.GetHelperMethod("ImportStar"), AstUtils.CodeContext(), Ast.Constant(_root.MakeString()), Ast.Constant(GetLevel()) ), Span ); } else { // from a[.b] import x [as xx], [ y [ as yy] ] [ , ... ] List<MSAst.Expression> statements = new List<MSAst.Expression>(); MSAst.ParameterExpression module = ag.GetTemporary("module"); // Create initializer of the array of names being passed to ImportWithNames MSAst.ConstantExpression[] names = new MSAst.ConstantExpression[_names.Length]; for (int i = 0; i < names.Length; i++) { names[i] = Ast.Constant(SymbolTable.IdToString(_names[i])); } // module = PythonOps.ImportWithNames(<context>, _root, make_array(_names)) statements.Add( ag.AddDebugInfo( AstUtils.Assign( module, Ast.Call( AstGenerator.GetHelperMethod("ImportWithNames"), AstUtils.CodeContext(), Ast.Constant(_root.MakeString()), Ast.NewArrayInit(typeof(string), names), Ast.Constant(GetLevel()) ) ), _root.Span ) ); // now load all the names being imported and assign the variables for (int i = 0; i < names.Length; i++) { statements.Add( ag.AddDebugInfo( AstUtils.Assign( _variables[i].Variable, Ast.Call( AstGenerator.GetHelperMethod("ImportFrom"), AstUtils.CodeContext(), module, names[i] ) ), Span ) ); } statements.Add(Ast.Empty()); return ag.AddDebugInfo(Ast.Block(statements.ToArray()), Span); } }
internal override MSAst.Expression TransformSet(AstGenerator ag, SourceSpan span, MSAst.Expression right, PythonOperationKind op) { // if we just have a simple named multi-assignment (e.g. a, b = 1,2) // then go ahead and step over the entire statement at once. If we have a // more complex statement (e.g. a.b, c.d = 1, 2) then we'll step over the // sets individually as they could be property sets the user wants to step // into. TODO: Enable stepping of the right hand side? bool emitIndividualSets = false; foreach (Expression e in _items) { if (IsComplexAssignment(e)) { emitIndividualSets = true; break; } } SourceSpan rightSpan = SourceSpan.None; SourceSpan leftSpan = (Span.Start.IsValid && span.IsValid) ? new SourceSpan(Span.Start, span.End) : SourceSpan.None; SourceSpan totalSpan = SourceSpan.None; if (emitIndividualSets) { rightSpan = span; leftSpan = SourceSpan.None; totalSpan = (Span.Start.IsValid && span.IsValid) ? new SourceSpan(Span.Start, span.End) : SourceSpan.None; } // 1. Evaluate the expression and assign the value to the temp. MSAst.ParameterExpression right_temp = ag.GetTemporary("unpacking"); // 2. Add the assignment "right_temp = right" into the suite/block MSAst.Expression assignStmt1 = AstGenerator.MakeAssignment(right_temp, right); // 3. Call GetEnumeratorValues on the right side (stored in temp) MSAst.Expression enumeratorValues = Ast.Call( AstGenerator.GetHelperMethod("GetEnumeratorValues"), // method // arguments ag.LocalContext, right_temp, AstUtils.Constant(_items.Length) ); // 4. Create temporary variable for the array MSAst.ParameterExpression array_temp = ag.GetTemporary("array", typeof(object[])); // 5. Assign the value of the method call (mce) into the array temp // And add the assignment "array_temp = Ops.GetEnumeratorValues(...)" into the block MSAst.Expression assignStmt2 = ag.MakeAssignment( array_temp, enumeratorValues, rightSpan ); ReadOnlyCollectionBuilder<MSAst.Expression> sets = new ReadOnlyCollectionBuilder<MSAst.Expression>(_items.Length + 1); for (int i = 0; i < _items.Length; i ++) { // target = array_temp[i] Expression target = _items[i]; if (target == null) { continue; } // 6. array_temp[i] MSAst.Expression element = Ast.ArrayAccess( array_temp, // array expression AstUtils.Constant(i) // index ); // 7. target = array_temp[i], and add the transformed assignment into the list of sets MSAst.Expression set = target.TransformSet( ag, emitIndividualSets ? // span target.Span : SourceSpan.None, element, PythonOperationKind.None ); sets.Add(set); } // 9. add the sets as their own block so they can be marked as a single span, if necessary. sets.Add(AstUtils.Empty()); MSAst.Expression itemSet = ag.AddDebugInfo(Ast.Block(sets.ToReadOnlyCollection()), leftSpan); // 10. Free the temps ag.FreeTemp(array_temp); ag.FreeTemp(right_temp); // 11. Return the suite statement (block) return ag.AddDebugInfo(Ast.Block(assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan); }
internal override MSAst.Expression Transform(AstGenerator ag) { string className = SymbolTable.IdToString(_name); AstGenerator builder = new AstGenerator(ag, className, false, "class " + className); // we always need to create a nested context for class defs builder.CreateNestedContext(); List<MSAst.Expression> init = new List<MSAst.Expression>(); CreateVariables(builder, init); // Create the body MSAst.Expression bodyStmt = builder.Transform(_body); MSAst.Expression modStmt = ag.Globals.Assign(ag.Globals.GetVariable(_modVariable), ag.Globals.GetVariable(_modNameVariable)); string doc = ag.GetDocumentation(_body); if (doc != null) { init.Add( ag.Globals.Assign( ag.Globals.GetVariable(_docVariable), AstUtils.Constant(doc) ) ); } bodyStmt = builder.WrapScopeStatements( Ast.Block( init.Count == 0 ? AstGenerator.EmptyBlock : Ast.Block(new ReadOnlyCollection<MSAst.Expression>(init)), modStmt, bodyStmt, builder.LocalContext // return value ) ); MSAst.LambdaExpression lambda = Ast.Lambda( typeof(Func<CodeContext>), builder.MakeBody(bodyStmt, true, false), builder.Name + "$" + _classId++, builder.Parameters ); MSAst.Expression classDef = Ast.Call( AstGenerator.GetHelperMethod("MakeClass"), lambda, ag.LocalContext, AstUtils.Constant(SymbolTable.IdToString(_name)), Ast.NewArrayInit( typeof(object), ag.TransformAndConvert(_bases, typeof(object)) ), AstUtils.Constant(FindSelfNames()) ); classDef = ag.AddDecorators(classDef, _decorators); return ag.AddDebugInfo(ag.Globals.Assign(ag.Globals.GetVariable(_variable), classDef), new SourceSpan(Start, Header)); }