PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 316 lines | 211 code | 22 blank | 83 comment | 8 complexity | b6fbcff285dd0a5754a40d2c3f77decf 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.Runtime.CompilerServices;
  18. using Microsoft.Scripting;
  19. using Microsoft.Scripting.Actions;
  20. using Microsoft.Scripting.Runtime;
  21. using IronPython.Runtime.Binding;
  22. #if !CLR2
  23. using MSAst = System.Linq.Expressions;
  24. #else
  25. using MSAst = Microsoft.Scripting.Ast;
  26. #endif
  27. using AstUtils = Microsoft.Scripting.Ast.Utils;
  28. namespace IronPython.Compiler.Ast {
  29. using Ast = MSAst.Expression;
  30. public class WithStatement : Statement {
  31. private SourceLocation _header;
  32. private readonly Expression _contextManager;
  33. private readonly Expression _var;
  34. private Statement _body;
  35. public WithStatement(Expression contextManager, Expression var, Statement body) {
  36. _contextManager = contextManager;
  37. _var = var;
  38. _body = body;
  39. }
  40. public SourceLocation Header {
  41. set { _header = value; }
  42. }
  43. public new Expression Variable {
  44. get { return _var; }
  45. }
  46. public Expression ContextManager {
  47. get { return _contextManager; }
  48. }
  49. public Statement Body {
  50. get { return _body; }
  51. }
  52. /// <summary>
  53. /// WithStatement is translated to the DLR AST equivalent to
  54. /// the following Python code snippet (from with statement spec):
  55. ///
  56. /// mgr = (EXPR)
  57. /// exit = mgr.__exit__ # Not calling it yet
  58. /// value = mgr.__enter__()
  59. /// exc = True
  60. /// try:
  61. /// VAR = value # Only if "as VAR" is present
  62. /// BLOCK
  63. /// except:
  64. /// # The exceptional case is handled here
  65. /// exc = False
  66. /// if not exit(*sys.exc_info()):
  67. /// raise
  68. /// # The exception is swallowed if exit() returns true
  69. /// finally:
  70. /// # The normal and non-local-goto cases are handled here
  71. /// if exc:
  72. /// exit(None, None, None)
  73. ///
  74. /// </summary>
  75. public override MSAst.Expression Reduce() {
  76. // Five statements in the result...
  77. ReadOnlyCollectionBuilder<MSAst.Expression> statements = new ReadOnlyCollectionBuilder<MSAst.Expression>(6);
  78. ReadOnlyCollectionBuilder<MSAst.ParameterExpression> variables = new ReadOnlyCollectionBuilder<MSAst.ParameterExpression>(6);
  79. MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with");
  80. variables.Add(lineUpdated);
  81. //******************************************************************
  82. // 1. mgr = (EXPR)
  83. //******************************************************************
  84. MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager");
  85. variables.Add(manager);
  86. statements.Add(
  87. GlobalParent.AddDebugInfo(
  88. Ast.Assign(
  89. manager,
  90. _contextManager
  91. ),
  92. new SourceSpan(Start, _header)
  93. )
  94. );
  95. //******************************************************************
  96. // 2. exit = mgr.__exit__ # Not calling it yet
  97. //******************************************************************
  98. MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit");
  99. variables.Add(exit);
  100. statements.Add(
  101. MakeAssignment(
  102. exit,
  103. GlobalParent.Get(
  104. "__exit__",
  105. manager
  106. )
  107. )
  108. );
  109. //******************************************************************
  110. // 3. value = mgr.__enter__()
  111. //******************************************************************
  112. MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value");
  113. variables.Add(value);
  114. statements.Add(
  115. GlobalParent.AddDebugInfoAndVoid(
  116. MakeAssignment(
  117. value,
  118. Parent.Invoke(
  119. new CallSignature(0),
  120. Parent.LocalContext,
  121. GlobalParent.Get(
  122. "__enter__",
  123. manager
  124. )
  125. )
  126. ),
  127. new SourceSpan(Start, _header)
  128. )
  129. );
  130. //******************************************************************
  131. // 4. exc = True
  132. //******************************************************************
  133. MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc");
  134. variables.Add(exc);
  135. statements.Add(
  136. MakeAssignment(
  137. exc,
  138. AstUtils.Constant(true)
  139. )
  140. );
  141. //******************************************************************
  142. // 5. The final try statement:
  143. //
  144. // try:
  145. // VAR = value # Only if "as VAR" is present
  146. // BLOCK
  147. // except:
  148. // # The exceptional case is handled here
  149. // exc = False
  150. // if not exit(*sys.exc_info()):
  151. // raise
  152. // # The exception is swallowed if exit() returns true
  153. // finally:
  154. // # The normal and non-local-goto cases are handled here
  155. // if exc:
  156. // exit(None, None, None)
  157. //******************************************************************
  158. MSAst.ParameterExpression exception;
  159. MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List<DynamicStackFrame>), "$nestedFrames");
  160. variables.Add(nestedFrames);
  161. statements.Add(
  162. // try:
  163. AstUtils.Try(
  164. AstUtils.Try(// try statement body
  165. PushLineUpdated(false, lineUpdated),
  166. _var != null ?
  167. (MSAst.Expression)Ast.Block(
  168. // VAR = value
  169. _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None),
  170. // BLOCK
  171. _body,
  172. AstUtils.Empty()
  173. ) :
  174. // BLOCK
  175. (MSAst.Expression)_body // except:, // try statement location
  176. ).Catch(exception = Ast.Variable(typeof(Exception), "exception"),
  177. // Python specific exception handling code
  178. TryStatement.GetTracebackHeader(
  179. this,
  180. exception,
  181. GlobalParent.AddDebugInfoAndVoid(
  182. Ast.Block(
  183. // exc = False
  184. MakeAssignment(
  185. exc,
  186. AstUtils.Constant(false)
  187. ),
  188. Ast.Assign(
  189. nestedFrames,
  190. Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
  191. ),
  192. // if not exit(*sys.exc_info()):
  193. // raise
  194. AstUtils.IfThen(
  195. GlobalParent.Convert(
  196. typeof(bool),
  197. ConversionResultKind.ExplicitCast,
  198. GlobalParent.Operation(
  199. typeof(bool),
  200. PythonOperationKind.IsFalse,
  201. MakeExitCall(exit, exception)
  202. )
  203. ),
  204. UpdateLineUpdated(true),
  205. Ast.Call(
  206. AstMethods.SetDynamicStackFrames,
  207. nestedFrames
  208. ),
  209. Ast.Throw(
  210. Ast.Call(
  211. AstMethods.MakeRethrowExceptionWorker,
  212. exception
  213. )
  214. )
  215. )
  216. ),
  217. _body.Span
  218. )
  219. ),
  220. Ast.Call(
  221. AstMethods.SetDynamicStackFrames,
  222. nestedFrames
  223. ),
  224. PopLineUpdated(lineUpdated),
  225. Ast.Empty()
  226. )
  227. // finally:
  228. ).Finally(
  229. // if exc:
  230. // exit(None, None, None)
  231. AstUtils.IfThen(
  232. exc,
  233. GlobalParent.AddDebugInfoAndVoid(
  234. Ast.Block(
  235. Ast.Dynamic(
  236. GlobalParent.PyContext.Invoke(
  237. new CallSignature(3) // signature doesn't include function
  238. ),
  239. typeof(object),
  240. new MSAst.Expression[] {
  241. Parent.LocalContext,
  242. exit,
  243. AstUtils.Constant(null),
  244. AstUtils.Constant(null),
  245. AstUtils.Constant(null)
  246. }
  247. ),
  248. Ast.Empty()
  249. ),
  250. _contextManager.Span
  251. )
  252. )
  253. )
  254. );
  255. statements.Add(AstUtils.Empty());
  256. return Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection());
  257. }
  258. private MSAst.Expression MakeExitCall(MSAst.ParameterExpression exit, MSAst.Expression exception) {
  259. // The 'with' statement's exceptional clause explicitly does not set the thread's current exception information.
  260. // So while the pseudo code says:
  261. // exit(*sys.exc_info())
  262. // we'll actually do:
  263. // exit(*PythonOps.GetExceptionInfoLocal($exception))
  264. return GlobalParent.Convert(
  265. typeof(bool),
  266. ConversionResultKind.ExplicitCast,
  267. Parent.Invoke(
  268. new CallSignature(ArgumentType.List),
  269. Parent.LocalContext,
  270. exit,
  271. Ast.Call(
  272. AstMethods.GetExceptionInfoLocal,
  273. Parent.LocalContext,
  274. exception
  275. )
  276. )
  277. );
  278. }
  279. public override void Walk(PythonWalker walker) {
  280. if (walker.Walk(this)) {
  281. if (_contextManager != null) {
  282. _contextManager.Walk(walker);
  283. }
  284. if (_var != null) {
  285. _var.Walk(walker);
  286. }
  287. if (_body != null) {
  288. _body.Walk(walker);
  289. }
  290. }
  291. walker.PostWalk(this);
  292. }
  293. }
  294. }