PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython/Compiler/Ast/FunctionDefinition.cs

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