PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 382 lines | 281 code | 69 blank | 32 comment | 42 complexity | 6b7ec9d85949f901f532a7e22b93b11a 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.Runtime.CompilerServices;
  20. using System.Threading;
  21. using Microsoft.Scripting;
  22. using Microsoft.Scripting.Runtime;
  23. using Microsoft.Scripting.Utils;
  24. using IronPython.Runtime;
  25. using IronPython.Runtime.Operations;
  26. #if !CLR2
  27. using MSAst = System.Linq.Expressions;
  28. #else
  29. using MSAst = Microsoft.Scripting.Ast;
  30. #endif
  31. using AstUtils = Microsoft.Scripting.Ast.Utils;
  32. namespace IronPython.Compiler.Ast {
  33. using Ast = MSAst.Expression;
  34. public class ClassDefinition : ScopeStatement {
  35. private SourceLocation _header;
  36. private readonly string _name;
  37. private Statement _body;
  38. private readonly Expression[] _bases;
  39. private IList<Expression> _decorators;
  40. private PythonVariable _variable; // Variable corresponding to the class name
  41. private PythonVariable _modVariable; // Variable for the the __module__ (module name)
  42. private PythonVariable _docVariable; // Variable for the __doc__ attribute
  43. private PythonVariable _modNameVariable; // Variable for the module's __name__
  44. private MSAst.LambdaExpression _dlrBody; // the transformed body including all of our initialization, etc...
  45. private static int _classId;
  46. private static MSAst.ParameterExpression _parentContextParam = Ast.Parameter(typeof(CodeContext), "$parentContext");
  47. private static MSAst.Expression _tupleExpression = MSAst.Expression.Call(AstMethods.GetClosureTupleFromContext, _parentContextParam);
  48. public ClassDefinition(string name, Expression[] bases, Statement body) {
  49. ContractUtils.RequiresNotNull(body, "body");
  50. ContractUtils.RequiresNotNullItems(bases, "bases");
  51. _name = name;
  52. _bases = bases;
  53. _body = body;
  54. }
  55. public SourceLocation Header {
  56. get { return _header; }
  57. set { _header = value; }
  58. }
  59. public override string Name {
  60. get { return _name; }
  61. }
  62. public IList<Expression> Bases {
  63. get { return _bases; }
  64. }
  65. public Statement Body {
  66. get { return _body; }
  67. }
  68. public IList<Expression> Decorators {
  69. get {
  70. return _decorators;
  71. }
  72. internal set {
  73. _decorators = value;
  74. }
  75. }
  76. internal PythonVariable PythonVariable {
  77. get { return _variable; }
  78. set { _variable = value; }
  79. }
  80. internal PythonVariable ModVariable {
  81. get { return _modVariable; }
  82. set { _modVariable = value; }
  83. }
  84. internal PythonVariable DocVariable {
  85. get { return _docVariable; }
  86. set { _docVariable = value; }
  87. }
  88. internal PythonVariable ModuleNameVariable {
  89. get { return _modNameVariable; }
  90. set { _modNameVariable = value; }
  91. }
  92. internal override bool HasLateBoundVariableSets {
  93. get {
  94. return base.HasLateBoundVariableSets || NeedsLocalsDictionary;
  95. }
  96. set {
  97. base.HasLateBoundVariableSets = value;
  98. }
  99. }
  100. internal override bool NeedsLocalContext {
  101. get {
  102. return true;
  103. }
  104. }
  105. internal override bool ExposesLocalVariable(PythonVariable variable) {
  106. return true;
  107. }
  108. internal override PythonVariable BindReference(PythonNameBinder binder, PythonReference reference) {
  109. PythonVariable variable;
  110. // Python semantics: The variables bound local in the class
  111. // scope are accessed by name - the dictionary behavior of classes
  112. if (TryGetVariable(reference.Name, out variable)) {
  113. // TODO: This results in doing a dictionary lookup to get/set the local,
  114. // when it should probably be an uninitialized check / global lookup for gets
  115. // and a direct set
  116. if (variable.Kind == VariableKind.Global) {
  117. AddReferencedGlobal(reference.Name);
  118. } else if (variable.Kind == VariableKind.Local) {
  119. return null;
  120. }
  121. return variable;
  122. }
  123. // Try to bind in outer scopes, if we have an unqualified exec we need to leave the
  124. // variables as free for the same reason that locals are accessed by name.
  125. for (ScopeStatement parent = Parent; parent != null; parent = parent.Parent) {
  126. if (parent.TryBindOuter(this, reference, out variable)) {
  127. return variable;
  128. }
  129. }
  130. return null;
  131. }
  132. public override MSAst.Expression Reduce() {
  133. var codeObj = GetOrMakeFunctionCode();
  134. var funcCode = GlobalParent.Constant(codeObj);
  135. FuncCodeExpr = funcCode;
  136. MSAst.Expression lambda;
  137. if (EmitDebugSymbols) {
  138. lambda = GetLambda();
  139. } else {
  140. lambda = Ast.Convert(funcCode, typeof(object));
  141. ThreadPool.QueueUserWorkItem((x) => {
  142. // class defs are almost always run, so start
  143. // compiling the code now so it might be ready
  144. // when we actually go and execute it
  145. codeObj.UpdateDelegate(PyContext, true);
  146. });
  147. }
  148. MSAst.Expression classDef = Ast.Call(
  149. AstMethods.MakeClass,
  150. lambda,
  151. Parent.LocalContext,
  152. AstUtils.Constant(_name),
  153. Ast.NewArrayInit(
  154. typeof(object),
  155. ToObjectArray(_bases)
  156. ),
  157. AstUtils.Constant(FindSelfNames())
  158. );
  159. classDef = AddDecorators(classDef, _decorators);
  160. return GlobalParent.AddDebugInfoAndVoid(AssignValue(Parent.GetVariableExpression(_variable), classDef), new SourceSpan(Start, Header));
  161. }
  162. private MSAst.Expression<Func<CodeContext, CodeContext>> MakeClassBody() {
  163. string className = _name;
  164. // we always need to create a nested context for class defs
  165. var init = new List<MSAst.Expression>();
  166. var locals = new ReadOnlyCollectionBuilder<MSAst.ParameterExpression>();
  167. locals.Add(LocalCodeContextVariable);
  168. locals.Add(PythonAst._globalContext);
  169. init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContextParam)));
  170. GlobalParent.PrepareScope(locals, init);
  171. CreateVariables(locals, init);
  172. var createLocal = CreateLocalContext(_parentContextParam);
  173. init.Add(Ast.Assign(LocalCodeContextVariable, createLocal));
  174. List<MSAst.Expression> statements = new List<MSAst.Expression>();
  175. // Create the body
  176. MSAst.Expression bodyStmt = _body;
  177. // __module__ = __name__
  178. MSAst.Expression modStmt = AssignValue(GetVariableExpression(_modVariable), GetVariableExpression(_modNameVariable));
  179. string doc = GetDocumentation(_body);
  180. if (doc != null) {
  181. statements.Add(
  182. AssignValue(
  183. GetVariableExpression(_docVariable),
  184. AstUtils.Constant(doc)
  185. )
  186. );
  187. }
  188. if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames) {
  189. bodyStmt = AddFrame(LocalContext, FuncCodeExpr, bodyStmt);
  190. locals.Add(FunctionStackVariable);
  191. }
  192. bodyStmt = WrapScopeStatements(
  193. Ast.Block(
  194. Ast.Block(init),
  195. statements.Count == 0 ?
  196. EmptyBlock :
  197. Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements)),
  198. modStmt,
  199. bodyStmt,
  200. LocalContext
  201. ),
  202. _body.CanThrow
  203. );
  204. var lambda = Ast.Lambda<Func<CodeContext, CodeContext>>(
  205. Ast.Block(
  206. locals,
  207. bodyStmt
  208. ),
  209. Name + "$" + Interlocked.Increment(ref _classId),
  210. new[] { _parentContextParam }
  211. );
  212. return lambda;
  213. }
  214. internal override MSAst.LambdaExpression GetLambda() {
  215. if (_dlrBody == null) {
  216. PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Creating FunctionBody");
  217. _dlrBody = MakeClassBody();
  218. }
  219. return _dlrBody;
  220. }
  221. /// <summary>
  222. /// Gets the closure tuple from our parent context.
  223. /// </summary>
  224. internal override MSAst.Expression GetParentClosureTuple() {
  225. return _tupleExpression;
  226. }
  227. internal override string ScopeDocumentation {
  228. get {
  229. return GetDocumentation(_body);
  230. }
  231. }
  232. public override void Walk(PythonWalker walker) {
  233. if (walker.Walk(this)) {
  234. if (_decorators != null) {
  235. foreach (Expression decorator in _decorators) {
  236. decorator.Walk(walker);
  237. }
  238. }
  239. if (_bases != null) {
  240. foreach (Expression b in _bases) {
  241. b.Walk(walker);
  242. }
  243. }
  244. if (_body != null) {
  245. _body.Walk(walker);
  246. }
  247. }
  248. walker.PostWalk(this);
  249. }
  250. private string FindSelfNames() {
  251. SuiteStatement stmts = Body as SuiteStatement;
  252. if (stmts == null) return "";
  253. foreach (Statement stmt in stmts.Statements) {
  254. FunctionDefinition def = stmt as FunctionDefinition;
  255. if (def != null && def.Name == "__init__") {
  256. return string.Join(",", SelfNameFinder.FindNames(def));
  257. }
  258. }
  259. return "";
  260. }
  261. private class SelfNameFinder : PythonWalker {
  262. private readonly FunctionDefinition _function;
  263. private readonly Parameter _self;
  264. public SelfNameFinder(FunctionDefinition function, Parameter self) {
  265. _function = function;
  266. _self = self;
  267. }
  268. public static string[] FindNames(FunctionDefinition function) {
  269. var parameters = function.Parameters;
  270. if (parameters.Count > 0) {
  271. SelfNameFinder finder = new SelfNameFinder(function, parameters[0]);
  272. function.Body.Walk(finder);
  273. return ArrayUtils.ToArray(finder._names.Keys);
  274. } else {
  275. // no point analyzing function with no parameters
  276. return ArrayUtils.EmptyStrings;
  277. }
  278. }
  279. private Dictionary<string, bool> _names = new Dictionary<string, bool>(StringComparer.Ordinal);
  280. private bool IsSelfReference(Expression expr) {
  281. NameExpression ne = expr as NameExpression;
  282. if (ne == null) return false;
  283. PythonVariable variable;
  284. if (_function.TryGetVariable(ne.Name, out variable) && variable == _self.PythonVariable) {
  285. return true;
  286. }
  287. return false;
  288. }
  289. // Don't recurse into class or function definitions
  290. public override bool Walk(ClassDefinition node) {
  291. return false;
  292. }
  293. public override bool Walk(FunctionDefinition node) {
  294. return false;
  295. }
  296. public override bool Walk(AssignmentStatement node) {
  297. foreach (Expression lhs in node.Left) {
  298. MemberExpression me = lhs as MemberExpression;
  299. if (me != null) {
  300. if (IsSelfReference(me.Target)) {
  301. _names[me.Name] = true;
  302. }
  303. }
  304. }
  305. return true;
  306. }
  307. }
  308. internal override void RewriteBody(PythonAst.LookupVisitor visitor) {
  309. _dlrBody = null;
  310. _body = new PythonAst.RewrittenBodyStatement(Body, visitor.Visit(Body));
  311. }
  312. }
  313. }