PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 486 lines | 350 code | 83 blank | 53 comment | 58 complexity | d2e9e1d708e0846728879c817b2231c8 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 Microsoft.Scripting;
  16. #if !CLR2
  17. using MSAst = System.Linq.Expressions;
  18. using System.Linq.Expressions;
  19. #else
  20. using MSAst = Microsoft.Scripting.Ast;
  21. #endif
  22. using System;
  23. using System.Collections.Generic;
  24. using System.Diagnostics;
  25. using Microsoft.Scripting.Actions;
  26. using Microsoft.Scripting.Ast;
  27. using Microsoft.Scripting.Runtime;
  28. using Microsoft.Scripting.Utils;
  29. using IronPython.Runtime;
  30. using IronPython.Runtime.Binding;
  31. using IronPython.Runtime.Operations;
  32. namespace IronPython.Compiler.Ast {
  33. using Ast = MSAst.Expression;
  34. using AstUtils = Microsoft.Scripting.Ast.Utils;
  35. public abstract class Node : MSAst.Expression {
  36. private ScopeStatement _parent;
  37. private SourceLocation _start = SourceLocation.Invalid;
  38. private SourceLocation _end = SourceLocation.Invalid;
  39. internal static readonly MSAst.BlockExpression EmptyBlock = Ast.Block(AstUtils.Empty());
  40. internal static readonly MSAst.Expression[] EmptyExpression = new MSAst.Expression[0];
  41. internal static MSAst.ParameterExpression FunctionStackVariable = Ast.Variable(typeof(List<FunctionStack>), "$funcStack");
  42. internal static readonly MSAst.LabelTarget GeneratorLabel = Ast.Label(typeof(object), "$generatorLabel");
  43. private static MSAst.ParameterExpression _lineNumberUpdated = Ast.Variable(typeof(bool), "$lineUpdated");
  44. private static readonly MSAst.ParameterExpression _lineNoVar = Ast.Parameter(typeof(int), "$lineNo");
  45. protected Node() {
  46. }
  47. #region Public API
  48. public ScopeStatement Parent {
  49. get { return _parent; }
  50. set { _parent = value; }
  51. }
  52. public void SetLoc(SourceLocation start, SourceLocation end) {
  53. _start = start;
  54. _end = end;
  55. }
  56. public void SetLoc(SourceSpan span) {
  57. _start = span.Start;
  58. _end = span.End;
  59. }
  60. public SourceLocation Start {
  61. get { return _start; }
  62. set { _start = value; }
  63. }
  64. public SourceLocation End {
  65. get { return _end; }
  66. set { _end = value; }
  67. }
  68. public SourceSpan Span {
  69. get {
  70. return new SourceSpan(_start, _end);
  71. }
  72. }
  73. public abstract void Walk(PythonWalker walker);
  74. public virtual string NodeName {
  75. get {
  76. return GetType().Name;
  77. }
  78. }
  79. #endregion
  80. #region Base Class Overrides
  81. /// <summary>
  82. /// Returns true if the node can throw, false otherwise. Used to determine
  83. /// whether or not we need to update the current dynamic stack info.
  84. /// </summary>
  85. internal virtual bool CanThrow {
  86. get {
  87. return true;
  88. }
  89. }
  90. public override bool CanReduce {
  91. get {
  92. return true;
  93. }
  94. }
  95. public override MSAst.ExpressionType NodeType {
  96. get {
  97. return MSAst.ExpressionType.Extension;
  98. }
  99. }
  100. public override string ToString() {
  101. return GetType().Name;
  102. }
  103. #endregion
  104. #region Internal APIs
  105. internal PythonAst GlobalParent {
  106. get {
  107. Node cur = this;
  108. while (!(cur is PythonAst)) {
  109. Debug.Assert(cur != null);
  110. cur = cur.Parent;
  111. }
  112. return (PythonAst)cur;
  113. }
  114. }
  115. internal bool EmitDebugSymbols {
  116. get {
  117. return GlobalParent.SourceUnit.EmitDebugSymbols;
  118. }
  119. }
  120. internal bool StripDocStrings {
  121. get {
  122. return GlobalParent.PyContext.PythonOptions.StripDocStrings;
  123. }
  124. }
  125. internal bool Optimize {
  126. get {
  127. return GlobalParent.PyContext.PythonOptions.Optimize;
  128. }
  129. }
  130. internal virtual string GetDocumentation(Statement/*!*/ stmt) {
  131. if (StripDocStrings) {
  132. return null;
  133. }
  134. return stmt.Documentation;
  135. }
  136. #endregion
  137. #region Transformation Helpers
  138. internal static MSAst.Expression[] ToObjectArray(IList<Expression> expressions) {
  139. MSAst.Expression[] to = new MSAst.Expression[expressions.Count];
  140. for (int i = 0; i < expressions.Count; i++) {
  141. to[i] = AstUtils.Convert(expressions[i], typeof(object));
  142. }
  143. return to;
  144. }
  145. internal static MSAst.Expression TransformOrConstantNull(Expression expression, Type/*!*/ type) {
  146. if (expression == null) {
  147. return AstUtils.Constant(null, type);
  148. } else {
  149. return AstUtils.Convert(expression, type);
  150. }
  151. }
  152. internal MSAst.Expression TransformAndDynamicConvert(Expression expression, Type/*!*/ type) {
  153. Debug.Assert(expression != null);
  154. MSAst.Expression res = expression;
  155. // Do we need conversion?
  156. if (!CanAssign(type, expression.Type)) {
  157. // ensure we're reduced before we check for dynamic expressions.
  158. var reduced = expression.Reduce();
  159. if (reduced is LightDynamicExpression) {
  160. reduced = reduced.Reduce();
  161. }
  162. // Add conversion step to the AST
  163. MSAst.DynamicExpression ae = reduced as MSAst.DynamicExpression;
  164. ReducableDynamicExpression rde = reduced as ReducableDynamicExpression;
  165. if ((ae != null && ae.Binder is PythonBinaryOperationBinder) ||
  166. (rde != null && rde.Binder is PythonBinaryOperationBinder)) {
  167. // create a combo site which does the conversion
  168. PythonBinaryOperationBinder binder;
  169. IList<MSAst.Expression> args;
  170. if (ae != null) {
  171. binder = (PythonBinaryOperationBinder)ae.Binder;
  172. args = ArrayUtils.ToArray(ae.Arguments);
  173. } else {
  174. binder = (PythonBinaryOperationBinder)rde.Binder;
  175. args = rde.Args;
  176. }
  177. ParameterMappingInfo[] infos = new ParameterMappingInfo[args.Count];
  178. for (int i = 0; i < infos.Length; i++) {
  179. infos[i] = ParameterMappingInfo.Parameter(i);
  180. }
  181. res = Expression.Dynamic(
  182. GlobalParent.PyContext.BinaryOperationRetType(
  183. binder,
  184. GlobalParent.PyContext.Convert(
  185. type,
  186. ConversionResultKind.ExplicitCast
  187. )
  188. ),
  189. type,
  190. args
  191. );
  192. } else {
  193. res = GlobalParent.Convert(
  194. type,
  195. ConversionResultKind.ExplicitCast,
  196. reduced
  197. );
  198. }
  199. }
  200. return res;
  201. }
  202. internal static bool CanAssign(Type/*!*/ to, Type/*!*/ from) {
  203. return to.IsAssignableFrom(from) && (to.IsValueType == from.IsValueType);
  204. }
  205. internal static MSAst.Expression/*!*/ ConvertIfNeeded(MSAst.Expression/*!*/ expression, Type/*!*/ type) {
  206. Debug.Assert(expression != null);
  207. // Do we need conversion?
  208. if (!CanAssign(type, expression.Type)) {
  209. // Add conversion step to the AST
  210. expression = AstUtils.Convert(expression, type);
  211. }
  212. return expression;
  213. }
  214. internal static MSAst.Expression TransformMaybeSingleLineSuite(Statement body, SourceLocation prevStart) {
  215. if (body.Start.Line != prevStart.Line) {
  216. return body;
  217. }
  218. MSAst.Expression res = body.Reduce();
  219. res = RemoveDebugInfo(prevStart.Line, res);
  220. if (res.Type != typeof(void)) {
  221. res = AstUtils.Void(res);
  222. }
  223. return res;
  224. }
  225. internal static MSAst.Expression RemoveDebugInfo(int prevStart, MSAst.Expression res) {
  226. MSAst.BlockExpression block = res as MSAst.BlockExpression;
  227. if (block != null && block.Expressions.Count > 0) {
  228. MSAst.DebugInfoExpression dbgInfo = block.Expressions[0] as MSAst.DebugInfoExpression;
  229. // body on the same line as an if, don't generate a 2nd sequence point
  230. if (dbgInfo != null && dbgInfo.StartLine == prevStart) {
  231. // we remove the debug info based upon how it's generated in DebugStatement.AddDebugInfo which is
  232. // the helper method which adds the debug info.
  233. if (block.Type == typeof(void)) {
  234. Debug.Assert(block.Expressions.Count == 3);
  235. Debug.Assert(block.Expressions[2] is MSAst.DebugInfoExpression && ((MSAst.DebugInfoExpression)block.Expressions[2]).IsClear);
  236. res = block.Expressions[1];
  237. } else {
  238. Debug.Assert(block.Expressions.Count == 4);
  239. Debug.Assert(block.Expressions[3] is MSAst.DebugInfoExpression && ((MSAst.DebugInfoExpression)block.Expressions[2]).IsClear);
  240. Debug.Assert(block.Expressions[1] is MSAst.BinaryExpression && ((MSAst.BinaryExpression)block.Expressions[2]).NodeType == MSAst.ExpressionType.Assign);
  241. res = ((MSAst.BinaryExpression)block.Expressions[1]).Right;
  242. }
  243. }
  244. }
  245. return res;
  246. }
  247. /// <summary>
  248. /// Creates a method frame for tracking purposes and enforces recursion
  249. /// </summary>
  250. internal static MSAst.Expression AddFrame(MSAst.Expression localContext, MSAst.Expression codeObject, MSAst.Expression body) {
  251. return new FramedCodeExpression(localContext, codeObject, body);
  252. }
  253. /// <summary>
  254. /// Removes the frames from generated code for when we're compiling the tracing delegate
  255. /// which will track the frames it's self.
  256. /// </summary>
  257. internal static MSAst.Expression RemoveFrame(MSAst.Expression expression) {
  258. return new FramedCodeVisitor().Visit(expression);
  259. }
  260. class FramedCodeVisitor : ExpressionVisitor {
  261. public override MSAst.Expression Visit(MSAst.Expression node) {
  262. FramedCodeExpression framedCode = node as FramedCodeExpression;
  263. if (framedCode != null) {
  264. return framedCode.Body;
  265. }
  266. return base.Visit(node);
  267. }
  268. }
  269. sealed class FramedCodeExpression : MSAst.Expression {
  270. private readonly MSAst.Expression _localContext, _codeObject, _body;
  271. public FramedCodeExpression(MSAst.Expression localContext, MSAst.Expression codeObject, MSAst.Expression body) {
  272. _localContext = localContext;
  273. _codeObject = codeObject;
  274. _body = body;
  275. }
  276. public override ExpressionType NodeType {
  277. get {
  278. return ExpressionType.Extension;
  279. }
  280. }
  281. public MSAst.Expression Body {
  282. get {
  283. return _body;
  284. }
  285. }
  286. public override MSAst.Expression Reduce() {
  287. return AstUtils.Try(
  288. Ast.Assign(
  289. FunctionStackVariable,
  290. Ast.Call(
  291. AstMethods.PushFrame,
  292. _localContext,
  293. _codeObject
  294. )
  295. ),
  296. _body
  297. ).Finally(
  298. Ast.Call(
  299. FunctionStackVariable,
  300. typeof(List<FunctionStack>).GetMethod("RemoveAt"),
  301. Ast.Add(
  302. Ast.Property(
  303. FunctionStackVariable,
  304. "Count"
  305. ),
  306. Ast.Constant(-1)
  307. )
  308. )
  309. );
  310. }
  311. public override Type Type {
  312. get {
  313. return _body.Type;
  314. }
  315. }
  316. public override bool CanReduce {
  317. get {
  318. return true;
  319. }
  320. }
  321. protected override MSAst.Expression VisitChildren(ExpressionVisitor visitor) {
  322. var localContext = visitor.Visit(_localContext);
  323. var codeObject = visitor.Visit(_codeObject);
  324. var body = visitor.Visit(_body);
  325. if (localContext != _localContext || _codeObject != codeObject || body != _body) {
  326. return new FramedCodeExpression(localContext, codeObject, body);
  327. }
  328. return this;
  329. }
  330. }
  331. internal static MSAst.Expression/*!*/ MakeAssignment(MSAst.ParameterExpression/*!*/ variable, MSAst.Expression/*!*/ right) {
  332. return Ast.Assign(variable, AstUtils.Convert(right, variable.Type));
  333. }
  334. internal MSAst.Expression MakeAssignment(MSAst.ParameterExpression variable, MSAst.Expression right, SourceSpan span) {
  335. return GlobalParent.AddDebugInfoAndVoid(Ast.Assign(variable, AstUtils.Convert(right, variable.Type)), span);
  336. }
  337. internal static MSAst.Expression/*!*/ AssignValue(MSAst.Expression/*!*/ expression, MSAst.Expression value) {
  338. Debug.Assert(expression != null);
  339. Debug.Assert(value != null);
  340. IPythonVariableExpression pyGlobal = expression as IPythonVariableExpression;
  341. if (pyGlobal != null) {
  342. return pyGlobal.Assign(value);
  343. }
  344. return Ast.Assign(expression, value);
  345. }
  346. internal static MSAst.Expression/*!*/ Delete(MSAst.Expression/*!*/ expression) {
  347. IPythonVariableExpression pyGlobal = expression as IPythonVariableExpression;
  348. if (pyGlobal != null) {
  349. return pyGlobal.Delete();
  350. }
  351. return Ast.Assign(expression, Ast.Field(null, typeof(Uninitialized).GetField("Instance")));
  352. }
  353. #endregion
  354. #region Basic Line Number Infrastructure
  355. /// <summary>
  356. /// A temporary variable to track if the current line number has been emitted via the fault update block.
  357. ///
  358. /// For example consider:
  359. ///
  360. /// try:
  361. /// raise Exception()
  362. /// except Exception, e:
  363. /// # do something here
  364. /// raise
  365. ///
  366. /// At "do something here" we need to have already emitted the line number, when we re-raise we shouldn't add it
  367. /// again. If we handled the exception then we should have set the bool back to false.
  368. ///
  369. /// We also sometimes directly check _lineNoUpdated to avoid creating this unless we have nested exceptions.
  370. /// </summary>
  371. internal static MSAst.ParameterExpression/*!*/ LineNumberUpdated {
  372. get {
  373. return _lineNumberUpdated;
  374. }
  375. }
  376. internal static MSAst.Expression UpdateLineNumber(int line) {
  377. return AstUtils.SkipInterpret(
  378. Ast.Assign(LineNumberExpression, AstUtils.Constant(line))
  379. );
  380. }
  381. internal static MSAst.Expression UpdateLineUpdated(bool updated) {
  382. return Ast.Assign(LineNumberUpdated, AstUtils.Constant(updated));
  383. }
  384. internal static MSAst.Expression PushLineUpdated(bool updated, MSAst.ParameterExpression saveCurrent) {
  385. return MSAst.Expression.Block(
  386. Ast.Assign(saveCurrent, LineNumberUpdated),
  387. Ast.Assign(LineNumberUpdated, AstUtils.Constant(updated))
  388. );
  389. }
  390. internal static MSAst.Expression PopLineUpdated(MSAst.ParameterExpression saveCurrent) {
  391. return Ast.Assign(LineNumberUpdated, saveCurrent);
  392. }
  393. /// <summary>
  394. /// A temporary variable to track the current line number
  395. /// </summary>
  396. internal static MSAst.ParameterExpression/*!*/ LineNumberExpression {
  397. get {
  398. return _lineNoVar;
  399. }
  400. }
  401. #endregion
  402. }
  403. }