PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/DICK.B1/IronPython/Compiler/Ast/FunctionDefinition.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 843 lines | 627 code | 142 blank | 74 comment | 118 complexity | a3d6d6bd2183ce0b7ad5cf63869761d9 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Collections.ObjectModel;
  18. using System.Diagnostics;
  19. using System.Reflection;
  20. using System.Text;
  21. using System.Threading;
  22. using System.Runtime.CompilerServices;
  23. using Microsoft.Scripting;
  24. using Microsoft.Scripting.Interpreter;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime;
  28. using IronPython.Runtime.Operations;
  29. #if !CLR2
  30. using MSAst = System.Linq.Expressions;
  31. #else
  32. using MSAst = Microsoft.Scripting.Ast;
  33. #endif
  34. using AstUtils = Microsoft.Scripting.Ast.Utils;
  35. using Debugging = Microsoft.Scripting.Debugging;
  36. namespace IronPython.Compiler.Ast {
  37. using Ast = MSAst.Expression;
  38. public class FunctionDefinition : ScopeStatement, IInstructionProvider {
  39. protected Statement _body;
  40. private SourceLocation _header;
  41. private readonly string _name;
  42. private readonly Parameter[] _parameters;
  43. private IList<Expression> _decorators;
  44. private bool _generator; // The function is a generator
  45. private bool _isLambda;
  46. // true if this function can set sys.exc_info(). Only functions with an except block can set that.
  47. private bool _canSetSysExcInfo;
  48. private bool _containsTryFinally; // true if the function contains try/finally, used for generator optimization
  49. private PythonVariable _variable; // The variable corresponding to the function name or null for lambdas
  50. internal PythonVariable _nameVariable; // the variable that refers to the global __name__
  51. private MSAst.LambdaExpression _dlrBody; // the transformed body including all of our initialization, etc...
  52. internal bool _hasReturn;
  53. private static int _lambdaId;
  54. internal static readonly MSAst.ParameterExpression _functionParam = Ast.Parameter(typeof(PythonFunction), "$function");
  55. private static readonly MSAst.Expression _GetClosureTupleFromFunctionCall = MSAst.Expression.Call(null, typeof(PythonOps).GetMethod("GetClosureTupleFromFunction"), _functionParam);
  56. private static readonly MSAst.Expression _parentContext = new GetParentContextFromFunctionExpression();
  57. internal static readonly MSAst.LabelTarget _returnLabel = MSAst.Expression.Label(typeof(object), "return");
  58. public FunctionDefinition(string name, Parameter[] parameters)
  59. : this(name, parameters, (Statement)null) {
  60. }
  61. public FunctionDefinition(string name, Parameter[] parameters, Statement body) {
  62. ContractUtils.RequiresNotNullItems(parameters, "parameters");
  63. if (name == null) {
  64. _name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
  65. _isLambda = true;
  66. } else {
  67. _name = name;
  68. }
  69. _parameters = parameters;
  70. _body = body;
  71. }
  72. [Obsolete("sourceUnit is now ignored. FunctionDefinitions should belong to a PythonAst which has a SourceUnit")]
  73. public FunctionDefinition(string name, Parameter[] parameters, SourceUnit sourceUnit)
  74. : this(name, parameters, (Statement)null) {
  75. }
  76. [Obsolete("sourceUnit is now ignored. FunctionDefinitions should belong to a PythonAst which has a SourceUnit")]
  77. public FunctionDefinition(string name, Parameter[] parameters, Statement body, SourceUnit sourceUnit)
  78. : this(name, parameters, body) {
  79. }
  80. internal override MSAst.Expression LocalContext {
  81. get {
  82. if (NeedsLocalsDictionary || ContainsNestedFreeVariables) {
  83. return base.LocalContext;
  84. }
  85. return GlobalParent.LocalContext;
  86. }
  87. }
  88. public bool IsLambda {
  89. get {
  90. return _isLambda;
  91. }
  92. }
  93. public IList<Parameter> Parameters {
  94. get { return _parameters; }
  95. }
  96. internal override string[] ParameterNames {
  97. get {
  98. return ArrayUtils.ConvertAll(_parameters, val => val.Name);
  99. }
  100. }
  101. internal override int ArgCount {
  102. get {
  103. return _parameters.Length;
  104. }
  105. }
  106. public Statement Body {
  107. get { return _body; }
  108. set { _body = value; }
  109. }
  110. public SourceLocation Header {
  111. get { return _header; }
  112. set { _header = value; }
  113. }
  114. public override string Name {
  115. get { return _name; }
  116. }
  117. public IList<Expression> Decorators {
  118. get { return _decorators; }
  119. internal set { _decorators = value; }
  120. }
  121. internal override bool IsGeneratorMethod {
  122. get {
  123. return IsGenerator;
  124. }
  125. }
  126. public bool IsGenerator {
  127. get { return _generator; }
  128. set { _generator = value; }
  129. }
  130. // Called by parser to mark that this function can set sys.exc_info().
  131. // An alternative technique would be to just walk the body after the parse and look for a except block.
  132. internal bool CanSetSysExcInfo {
  133. set { _canSetSysExcInfo = value; }
  134. }
  135. internal bool ContainsTryFinally {
  136. get { return _containsTryFinally; }
  137. set { _containsTryFinally = value; }
  138. }
  139. internal PythonVariable PythonVariable {
  140. get { return _variable; }
  141. set { _variable = value; }
  142. }
  143. internal override bool ExposesLocalVariable(PythonVariable variable) {
  144. return NeedsLocalsDictionary;
  145. }
  146. internal override FunctionAttributes Flags {
  147. get {
  148. FunctionAttributes fa = FunctionAttributes.None;
  149. if (_parameters != null) {
  150. int i;
  151. for (i = 0; i < _parameters.Length; i++) {
  152. Parameter p = _parameters[i];
  153. if (p.IsDictionary || p.IsList) break;
  154. }
  155. // Check for the list and dictionary parameters, which must be the last(two)
  156. if (i < _parameters.Length && _parameters[i].IsList) {
  157. i++;
  158. fa |= FunctionAttributes.ArgumentList;
  159. }
  160. if (i < _parameters.Length && _parameters[i].IsDictionary) {
  161. i++;
  162. fa |= FunctionAttributes.KeywordDictionary;
  163. }
  164. // All parameters must now be exhausted
  165. Debug.Assert(i == _parameters.Length);
  166. }
  167. if (_canSetSysExcInfo) {
  168. fa |= FunctionAttributes.CanSetSysExcInfo;
  169. }
  170. if (ContainsTryFinally) {
  171. fa |= FunctionAttributes.ContainsTryFinally;
  172. }
  173. if (IsGenerator) {
  174. fa |= FunctionAttributes.Generator;
  175. }
  176. return fa;
  177. }
  178. }
  179. internal override bool TryBindOuter(ScopeStatement from, PythonReference reference, out PythonVariable variable) {
  180. // Functions expose their locals to direct access
  181. ContainsNestedFreeVariables = true;
  182. if (TryGetVariable(reference.Name, out variable)) {
  183. variable.AccessedInNestedScope = true;
  184. if (variable.Kind == VariableKind.Local || variable.Kind == VariableKind.Parameter) {
  185. from.AddFreeVariable(variable, true);
  186. for (ScopeStatement scope = from.Parent; scope != this; scope = scope.Parent) {
  187. scope.AddFreeVariable(variable, false);
  188. }
  189. AddCellVariable(variable);
  190. } else {
  191. from.AddReferencedGlobal(reference.Name);
  192. }
  193. return true;
  194. }
  195. return false;
  196. }
  197. internal override PythonVariable BindReference(PythonNameBinder binder, PythonReference reference) {
  198. PythonVariable variable;
  199. // First try variables local to this scope
  200. if (TryGetVariable(reference.Name, out variable)) {
  201. if (variable.Kind == VariableKind.Global) {
  202. AddReferencedGlobal(reference.Name);
  203. }
  204. return variable;
  205. }
  206. // Try to bind in outer scopes
  207. for (ScopeStatement parent = Parent; parent != null; parent = parent.Parent) {
  208. if (parent.TryBindOuter(this, reference, out variable)) {
  209. return variable;
  210. }
  211. }
  212. return null;
  213. }
  214. internal override void Bind(PythonNameBinder binder) {
  215. base.Bind(binder);
  216. Verify(binder);
  217. if (((PythonContext)binder.Context.SourceUnit.LanguageContext).PythonOptions.FullFrames) {
  218. // force a dictionary if we have enabled full frames for sys._getframe support
  219. NeedsLocalsDictionary = true;
  220. }
  221. }
  222. internal override void FinishBind(PythonNameBinder binder) {
  223. foreach (var param in _parameters) {
  224. _variableMapping[param.PythonVariable] = param.FinishBind(NeedsLocalsDictionary);
  225. }
  226. base.FinishBind(binder);
  227. }
  228. private void Verify(PythonNameBinder binder) {
  229. if (ContainsImportStar && IsClosure) {
  230. binder.ReportSyntaxError(
  231. String.Format(
  232. System.Globalization.CultureInfo.InvariantCulture,
  233. "import * is not allowed in function '{0}' because it is a nested function",
  234. Name),
  235. this);
  236. }
  237. if (ContainsImportStar && Parent is FunctionDefinition) {
  238. binder.ReportSyntaxError(
  239. String.Format(
  240. System.Globalization.CultureInfo.InvariantCulture,
  241. "import * is not allowed in function '{0}' because it is a nested function",
  242. Name),
  243. this);
  244. }
  245. if (ContainsImportStar && ContainsNestedFreeVariables) {
  246. binder.ReportSyntaxError(
  247. String.Format(
  248. System.Globalization.CultureInfo.InvariantCulture,
  249. "import * is not allowed in function '{0}' because it contains a nested function with free variables",
  250. Name),
  251. this);
  252. }
  253. if (ContainsUnqualifiedExec && ContainsNestedFreeVariables) {
  254. binder.ReportSyntaxError(
  255. String.Format(
  256. System.Globalization.CultureInfo.InvariantCulture,
  257. "unqualified exec is not allowed in function '{0}' because it contains a nested function with free variables",
  258. Name),
  259. this);
  260. }
  261. if (ContainsUnqualifiedExec && IsClosure) {
  262. binder.ReportSyntaxError(
  263. String.Format(
  264. System.Globalization.CultureInfo.InvariantCulture,
  265. "unqualified exec is not allowed in function '{0}' because it is a nested function",
  266. Name),
  267. this);
  268. }
  269. }
  270. /// <summary>
  271. /// Pulls the closure tuple from our function/generator which is flowed into each function call.
  272. /// </summary>
  273. internal override MSAst.Expression/*!*/ GetParentClosureTuple() {
  274. return _GetClosureTupleFromFunctionCall;
  275. }
  276. public override MSAst.Expression Reduce() {
  277. Debug.Assert(_variable != null, "Shouldn't be called by lambda expression");
  278. MSAst.Expression function = MakeFunctionExpression();
  279. return GlobalParent.AddDebugInfoAndVoid(AssignValue(Parent.GetVariableExpression(_variable), function), new SourceSpan(Start, Header));
  280. }
  281. /// <summary>
  282. /// Returns an expression which creates the function object.
  283. /// </summary>
  284. internal MSAst.Expression MakeFunctionExpression() {
  285. List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
  286. foreach (var param in _parameters) {
  287. if (param.DefaultValue != null) {
  288. defaults.Add(AstUtils.Convert(param.DefaultValue, typeof(object)));
  289. }
  290. }
  291. MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode());
  292. FuncCodeExpr = funcCode;
  293. MSAst.Expression ret;
  294. if (EmitDebugFunction()) {
  295. MSAst.LambdaExpression code = EnsureFunctionLambda();
  296. // we need to compile all of the debuggable code together at once otherwise mdbg gets confused. If we're
  297. // in tracing mode we'll still compile things one off though just to keep things simple. The code will still
  298. // be debuggable but naive debuggers like mdbg will have more issues.
  299. ret = Ast.Call(
  300. AstMethods.MakeFunctionDebug, // method
  301. Parent.LocalContext, // 1. Emit CodeContext
  302. FuncCodeExpr, // 2. FunctionCode
  303. ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(), // 3. module name
  304. defaults.Count == 0 ? // 4. default values
  305. AstUtils.Constant(null, typeof(object[])) :
  306. (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
  307. IsGenerator ?
  308. (MSAst.Expression)new PythonGeneratorExpression(code, GlobalParent.PyContext.Options.CompilationThreshold) :
  309. (MSAst.Expression)code
  310. );
  311. } else {
  312. ret = Ast.Call(
  313. AstMethods.MakeFunction, // method
  314. Parent.LocalContext, // 1. Emit CodeContext
  315. FuncCodeExpr, // 2. FunctionCode
  316. ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(), // 3. module name
  317. defaults.Count == 0 ? // 4. default values
  318. AstUtils.Constant(null, typeof(object[])) :
  319. (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults)
  320. );
  321. }
  322. return AddDecorators(ret, _decorators);
  323. }
  324. #region IInstructionProvider Members
  325. void IInstructionProvider.AddInstructions(LightCompiler compiler) {
  326. if (_decorators != null) {
  327. // decorators aren't supported, skip using the optimized instruction.
  328. compiler.Compile(Reduce());
  329. return;
  330. }
  331. // currently needed so we can later compile
  332. MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode());
  333. FuncCodeExpr = funcCode;
  334. var variable = Parent.GetVariableExpression(_variable);
  335. CompileAssignment(compiler, variable, CreateFunctionInstructions);
  336. }
  337. private void CreateFunctionInstructions(LightCompiler compiler) {
  338. // emit context if we have a special local context
  339. CodeContext globalContext = null;
  340. compiler.Compile(Parent.LocalContext);
  341. // emit name if necessary
  342. PythonGlobalVariableExpression name = GetVariableExpression(_nameVariable) as PythonGlobalVariableExpression;
  343. PythonGlobal globalName = null;
  344. if (name == null) {
  345. compiler.Compile(((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue());
  346. } else {
  347. globalName = name.Global;
  348. }
  349. // emit defaults
  350. int defaultCount = 0;
  351. for (int i = _parameters.Length - 1; i >= 0; i--) {
  352. var param = _parameters[i];
  353. if (param.DefaultValue != null) {
  354. compiler.Compile(AstUtils.Convert(param.DefaultValue, typeof(object)));
  355. defaultCount++;
  356. }
  357. }
  358. compiler.Instructions.Emit(new FunctionDefinitionInstruction(globalContext, this, defaultCount, globalName));
  359. }
  360. private static void CompileAssignment(LightCompiler compiler, MSAst.Expression variable, Action<LightCompiler> compileValue) {
  361. var instructions = compiler.Instructions;
  362. ClosureExpression closure = variable as ClosureExpression;
  363. if (closure != null) {
  364. compiler.Compile(closure.ClosureCell);
  365. }
  366. LookupGlobalVariable lookup = variable as LookupGlobalVariable;
  367. if (lookup != null) {
  368. compiler.Compile(lookup.CodeContext);
  369. instructions.EmitLoad(lookup.Name);
  370. }
  371. compileValue(compiler);
  372. if (closure != null) {
  373. instructions.EmitStoreField(ClosureExpression._cellField);
  374. return;
  375. }
  376. if (lookup != null) {
  377. instructions.EmitCall(typeof(PythonOps).GetMethod(lookup.IsLocal ? "SetLocal" : "SetGlobal"));
  378. return;
  379. }
  380. MSAst.ParameterExpression functionValueParam = variable as MSAst.ParameterExpression;
  381. if (functionValueParam != null) {
  382. instructions.EmitStoreLocal(compiler.Locals.GetVariableIndex(functionValueParam));
  383. return;
  384. }
  385. var globalVar = variable as PythonGlobalVariableExpression;
  386. if (globalVar != null) {
  387. instructions.Emit(new PythonSetGlobalInstruction(globalVar.Global));
  388. instructions.EmitPop();
  389. return;
  390. }
  391. Debug.Assert(false, "Unsupported variable type for light compiling function");
  392. }
  393. class FunctionDefinitionInstruction : Instruction {
  394. private readonly FunctionDefinition _def;
  395. private readonly int _defaultCount;
  396. private readonly CodeContext _context;
  397. private readonly PythonGlobal _name;
  398. public FunctionDefinitionInstruction(CodeContext context, FunctionDefinition/*!*/ definition, int defaultCount, PythonGlobal name) {
  399. Assert.NotNull(definition);
  400. _context = context;
  401. _defaultCount = defaultCount;
  402. _def = definition;
  403. _name = name;
  404. }
  405. public override int Run(InterpretedFrame frame) {
  406. object[] defaults;
  407. if (_defaultCount > 0) {
  408. defaults = new object[_defaultCount];
  409. for (int i = 0; i < _defaultCount; i++) {
  410. defaults[i] = frame.Pop();
  411. }
  412. } else {
  413. defaults = ArrayUtils.EmptyObjects;
  414. }
  415. object modName;
  416. if (_name != null) {
  417. modName = _name.RawValue;
  418. } else {
  419. modName = frame.Pop();
  420. }
  421. CodeContext context = (CodeContext)frame.Pop();
  422. frame.Push(PythonOps.MakeFunction(context, _def.FunctionCode, modName, defaults));
  423. return +1;
  424. }
  425. public override int ConsumedStack {
  426. get {
  427. return _defaultCount +
  428. (_context == null ? 1 : 0) +
  429. (_name == null ? 1 : 0);
  430. }
  431. }
  432. public override int ProducedStack {
  433. get {
  434. return 1;
  435. }
  436. }
  437. }
  438. #endregion
  439. /// <summary>
  440. /// Creates the LambdaExpression which is the actual function body.
  441. /// </summary>
  442. private MSAst.LambdaExpression EnsureFunctionLambda() {
  443. if (_dlrBody == null) {
  444. PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Creating FunctionBody");
  445. _dlrBody = CreateFunctionLambda();
  446. }
  447. return _dlrBody;
  448. }
  449. internal override Delegate OriginalDelegate {
  450. get {
  451. Delegate originalDelegate;
  452. bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs;
  453. GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate);
  454. return originalDelegate;
  455. }
  456. }
  457. internal override string ScopeDocumentation {
  458. get {
  459. return GetDocumentation(_body);
  460. }
  461. }
  462. /// <summary>
  463. /// Creates the LambdaExpression which implements the body of the function.
  464. ///
  465. /// The functions signature is either "object Function(PythonFunction, ...)"
  466. /// where there is one object parameter for each user defined parameter or
  467. /// object Function(PythonFunction, object[]) for functions which take more
  468. /// than PythonCallTargets.MaxArgs arguments.
  469. /// </summary>
  470. private MSAst.LambdaExpression CreateFunctionLambda() {
  471. bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs;
  472. Delegate originalDelegate;
  473. Type delegateType = GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate);
  474. MSAst.ParameterExpression localContext = null;
  475. ReadOnlyCollectionBuilder<MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder<MSAst.ParameterExpression>();
  476. if (NeedsLocalsDictionary || ContainsNestedFreeVariables) {
  477. localContext = LocalCodeContextVariable;
  478. locals.Add(localContext);
  479. }
  480. MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals);
  481. List<MSAst.Expression> init = new List<MSAst.Expression>();
  482. foreach (var param in _parameters) {
  483. IPythonVariableExpression pyVar = GetVariableExpression(param.PythonVariable) as IPythonVariableExpression;
  484. if (pyVar != null) {
  485. var varInit = pyVar.Create();
  486. if (varInit != null) {
  487. init.Add(varInit);
  488. }
  489. }
  490. }
  491. // Transform the parameters.
  492. init.Add(Ast.ClearDebugInfo(GlobalParent.Document));
  493. locals.Add(PythonAst._globalContext);
  494. init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext)));
  495. GlobalParent.PrepareScope(locals, init);
  496. // Create variables and references. Since references refer to
  497. // parameters, do this after parameters have been created.
  498. CreateFunctionVariables(locals, init);
  499. // Initialize parameters - unpack tuples.
  500. // Since tuples unpack into locals, this must be done after locals have been created.
  501. InitializeParameters(init, needsWrapperMethod, parameters);
  502. List<MSAst.Expression> statements = new List<MSAst.Expression>();
  503. // add beginning sequence point
  504. statements.Add(GlobalParent.AddDebugInfo(
  505. AstUtils.Empty(),
  506. new SourceSpan(new SourceLocation(0, Start.Line, Start.Column), new SourceLocation(0, Start.Line, Int32.MaxValue))));
  507. // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close().
  508. // The exception traceback needs to come from the generator's method body, and so we must do the check and throw
  509. // from inside the generator.
  510. if (IsGenerator) {
  511. MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(SourceSpan.None);
  512. statements.Add(s1);
  513. }
  514. MSAst.ParameterExpression extracted = null;
  515. if (!IsGenerator && _canSetSysExcInfo) {
  516. // need to allocate the exception here so we don't share w/ exceptions made & freed
  517. // during the body.
  518. extracted = Ast.Parameter(typeof(Exception), "$ex");
  519. locals.Add(extracted);
  520. }
  521. if (_body.CanThrow && !(_body is SuiteStatement) && _body.Start.IsValid) {
  522. statements.Add(UpdateLineNumber(_body.Start.Line));
  523. }
  524. statements.Add(Body);
  525. MSAst.Expression body = Ast.Block(statements);
  526. // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish.
  527. //
  528. // Wrap in
  529. // $temp = PythonOps.SaveCurrentException()
  530. // <body>
  531. // PythonOps.RestoreCurrentException($temp)
  532. // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class
  533. // before it's invoked. This is because the restoration must occur at every place the function returns from
  534. // a yield point. That's different than the finally semantics in a generator.
  535. if (extracted != null) {
  536. MSAst.Expression s = AstUtils.Try(
  537. Ast.Assign(
  538. extracted,
  539. Ast.Call(AstMethods.SaveCurrentException)
  540. ),
  541. body
  542. ).Finally(
  543. Ast.Call(
  544. AstMethods.RestoreCurrentException, extracted
  545. )
  546. );
  547. body = s;
  548. }
  549. if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames) {
  550. body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body);
  551. locals.Add(FunctionStackVariable);
  552. }
  553. body = AddProfiling(body);
  554. body = WrapScopeStatements(body, _body.CanThrow);
  555. body = Ast.Block(body, AstUtils.Empty());
  556. body = AddReturnTarget(body);
  557. MSAst.Expression bodyStmt = body;
  558. if (localContext != null) {
  559. var createLocal = CreateLocalContext(_parentContext);
  560. init.Add(
  561. Ast.Assign(
  562. localContext,
  563. createLocal
  564. )
  565. );
  566. }
  567. init.Add(bodyStmt);
  568. bodyStmt = Ast.Block(init);
  569. // wrap a scope if needed
  570. bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt);
  571. return Ast.Lambda(
  572. delegateType,
  573. AddDefaultReturn(bodyStmt, typeof(object)),
  574. Name + "$" + Interlocked.Increment(ref _lambdaId),
  575. parameters
  576. );
  577. }
  578. internal override MSAst.LambdaExpression GetLambda() {
  579. return EnsureFunctionLambda();
  580. }
  581. internal FunctionCode FunctionCode {
  582. get {
  583. return GetOrMakeFunctionCode();
  584. }
  585. }
  586. private static MSAst.Expression/*!*/ AddDefaultReturn(MSAst.Expression/*!*/ body, Type returnType) {
  587. if (body.Type == typeof(void) && returnType != typeof(void)) {
  588. body = Ast.Block(body, Ast.Default(returnType));
  589. }
  590. return body;
  591. }
  592. private MSAst.ParameterExpression[] CreateParameters(bool needsWrapperMethod, ReadOnlyCollectionBuilder<MSAst.ParameterExpression> locals) {
  593. MSAst.ParameterExpression[] parameters;
  594. if (needsWrapperMethod) {
  595. parameters = new[] { _functionParam, Ast.Parameter(typeof(object[]), "allArgs") };
  596. foreach (var param in _parameters) {
  597. locals.Add(param.ParameterExpression);
  598. }
  599. } else {
  600. parameters = new MSAst.ParameterExpression[_parameters.Length + 1];
  601. for (int i = 1; i < parameters.Length; i++) {
  602. parameters[i] = _parameters[i - 1].ParameterExpression;
  603. }
  604. parameters[0] = _functionParam;
  605. }
  606. return parameters;
  607. }
  608. internal void CreateFunctionVariables(ReadOnlyCollectionBuilder<MSAst.ParameterExpression> locals, List<MSAst.Expression> init) {
  609. CreateVariables(locals, init);
  610. }
  611. internal MSAst.Expression/*!*/ AddReturnTarget(MSAst.Expression/*!*/ expression) {
  612. if (_hasReturn) {
  613. return Ast.Label(_returnLabel, AstUtils.Convert(expression, typeof(object)));
  614. }
  615. return expression;
  616. }
  617. internal override string ProfilerName {
  618. get {
  619. var sb = new StringBuilder("def ");
  620. sb.Append(Name);
  621. sb.Append('(');
  622. bool comma = false;
  623. foreach (var p in _parameters) {
  624. if (comma) {
  625. sb.Append(", ");
  626. } else {
  627. comma = true;
  628. }
  629. sb.Append(p.Name);
  630. }
  631. sb.Append(')');
  632. return sb.ToString();
  633. }
  634. }
  635. private bool EmitDebugFunction() {
  636. return EmitDebugSymbols && !GlobalParent.PyContext.EnableTracing;
  637. }
  638. internal override IList<string> GetVarNames() {
  639. List<string> res = new List<string>();
  640. foreach (Parameter p in _parameters) {
  641. res.Add(p.Name);
  642. }
  643. AppendVariables(res);
  644. return res;
  645. }
  646. private void InitializeParameters(List<MSAst.Expression> init, bool needsWrapperMethod, MSAst.Expression[] parameters) {
  647. for (int i = 0; i < _parameters.Length; i++) {
  648. Parameter p = _parameters[i];
  649. if (needsWrapperMethod) {
  650. // if our method signature is object[] we need to first unpack the argument
  651. // from the incoming array.
  652. init.Add(
  653. AssignValue(
  654. GetVariableExpression(p.PythonVariable),
  655. Ast.ArrayIndex(
  656. parameters[1],
  657. Ast.Constant(i)
  658. )
  659. )
  660. );
  661. }
  662. p.Init(init);
  663. }
  664. }
  665. public override void Walk(PythonWalker walker) {
  666. if (walker.Walk(this)) {
  667. if (_parameters != null) {
  668. foreach (Parameter p in _parameters) {
  669. p.Walk(walker);
  670. }
  671. }
  672. if (_decorators != null) {
  673. foreach (Expression decorator in _decorators) {
  674. decorator.Walk(walker);
  675. }
  676. }
  677. if (_body != null) {
  678. _body.Walk(walker);
  679. }
  680. }
  681. walker.PostWalk(this);
  682. }
  683. /// <summary>
  684. /// Determines delegate type for the Python function
  685. /// </summary>
  686. private static Type GetDelegateType(Parameter[] parameters, bool wrapper, out Delegate originalTarget) {
  687. return PythonCallTargets.GetPythonTargetType(wrapper, parameters.Length, out originalTarget);
  688. }
  689. internal override bool CanThrow {
  690. get {
  691. return false;
  692. }
  693. }
  694. internal override void RewriteBody(PythonAst.LookupVisitor visitor) {
  695. _dlrBody = null; // clear the cached body if we've been reduced
  696. MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode());
  697. FuncCodeExpr = funcCode;
  698. Body = new PythonAst.RewrittenBodyStatement(Body, visitor.Visit(Body));
  699. }
  700. }
  701. }