PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 903 lines | 684 code | 135 blank | 84 comment | 119 complexity | 0cfb4bac1410ca87008d9a0e96897999 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.Diagnostics;
  18. using System.Reflection;
  19. using System.Runtime.CompilerServices;
  20. using Microsoft.Scripting;
  21. using Microsoft.Scripting.Actions;
  22. using Microsoft.Scripting.Ast;
  23. using Microsoft.Scripting.Interpreter;
  24. using Microsoft.Scripting.Runtime;
  25. using Microsoft.Scripting.Utils;
  26. using IronPython.Runtime;
  27. using IronPython.Runtime.Binding;
  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. namespace IronPython.Compiler.Ast {
  35. using Ast = MSAst.Expression;
  36. using AstUtils = Microsoft.Scripting.Ast.Utils;
  37. public abstract class ScopeStatement : Statement {
  38. private bool _importStar; // from module import *
  39. private bool _unqualifiedExec; // exec "code"
  40. private bool _nestedFreeVariables; // nested function with free variable
  41. private bool _locals; // The scope needs locals dictionary
  42. // due to "exec" or call to dir, locals, eval, vars...
  43. private bool _hasLateboundVarSets; // calls code which can assign to variables
  44. private bool _containsExceptionHandling; // true if this block contains a try/with statement
  45. private bool _forceCompile; // true if this scope should always be compiled
  46. private FunctionCode _funcCode; // the function code object created for this scope
  47. private Dictionary<string, PythonVariable> _variables; // mapping of string to variables
  48. private ClosureInfo[] _closureVariables; // closed over variables, bool indicates if we accessed it in this scope.
  49. private List<PythonVariable> _freeVars; // list of variables accessed from outer scopes
  50. private List<string> _globalVars; // global variables accessed from this scope
  51. private List<string> _cellVars; // variables accessed from nested scopes
  52. private Dictionary<string, PythonReference> _references; // names of all variables referenced, null after binding completes
  53. internal Dictionary<PythonVariable, MSAst.Expression> _variableMapping = new Dictionary<PythonVariable, MSAst.Expression>();
  54. private MSAst.Expression _saveLineNumberAdds, _saveLineNumberNoAdds; // line number update expressions, saved so we don't repeatedly re-generate them
  55. private MSAst.ParameterExpression _localParentTuple; // parent's tuple local saved locally
  56. private readonly DelayedFunctionCode _funcCodeExpr = new DelayedFunctionCode(); // expression that refers to the function code for this scope
  57. internal static MSAst.ParameterExpression LocalCodeContextVariable = Ast.Parameter(typeof(CodeContext), "$localContext");
  58. private static readonly MSAst.Expression _GetCurrentMethod = Ast.Call(AstMethods.GetCurrentMethod);
  59. internal const string NameForExec = "module: <exec>";
  60. internal bool ContainsImportStar {
  61. get { return _importStar; }
  62. set { _importStar = value; }
  63. }
  64. internal bool ContainsExceptionHandling {
  65. get {
  66. return _containsExceptionHandling;
  67. }
  68. set {
  69. _containsExceptionHandling = value;
  70. }
  71. }
  72. internal bool ContainsUnqualifiedExec {
  73. get { return _unqualifiedExec; }
  74. set { _unqualifiedExec = value; }
  75. }
  76. internal virtual bool IsGeneratorMethod {
  77. get {
  78. return false;
  79. }
  80. }
  81. /// <summary>
  82. /// The variable used to hold out parents closure tuple in our local scope.
  83. /// </summary>
  84. internal MSAst.ParameterExpression LocalParentTuple {
  85. get {
  86. return _localParentTuple;
  87. }
  88. }
  89. /// <summary>
  90. /// Gets the expression associated with the local CodeContext. If the function
  91. /// doesn't have a local CodeContext then this is the global context.
  92. /// </summary>
  93. internal virtual MSAst.Expression LocalContext {
  94. get {
  95. return LocalCodeContextVariable;
  96. }
  97. }
  98. /// <summary>
  99. /// True if this scope accesses a variable from an outer scope.
  100. /// </summary>
  101. internal bool IsClosure {
  102. get { return FreeVariables != null && FreeVariables.Count > 0; }
  103. }
  104. /// <summary>
  105. /// True if an inner scope is accessing a variable defined in this scope.
  106. /// </summary>
  107. internal bool ContainsNestedFreeVariables {
  108. get { return _nestedFreeVariables; }
  109. set { _nestedFreeVariables = value; }
  110. }
  111. /// <summary>
  112. /// True if we are forcing the creation of a dictionary for storing locals.
  113. ///
  114. /// This occurs for calls to locals(), dir(), vars(), unqualified exec, and
  115. /// from ... import *.
  116. /// </summary>
  117. internal bool NeedsLocalsDictionary {
  118. get { return _locals; }
  119. set { _locals = value; }
  120. }
  121. public virtual string Name {
  122. get {
  123. return "<unknown>";
  124. }
  125. }
  126. internal virtual string Filename {
  127. get {
  128. return GlobalParent.SourceUnit.Path ?? "<string>";
  129. }
  130. }
  131. /// <summary>
  132. /// True if variables can be set in a late bound fashion that we don't
  133. /// know about at code gen time - for example via from foo import *.
  134. ///
  135. /// This is tracked independently of the ContainsUnqualifiedExec/NeedsLocalsDictionary
  136. /// </summary>
  137. internal virtual bool HasLateBoundVariableSets {
  138. get {
  139. return _hasLateboundVarSets;
  140. }
  141. set {
  142. _hasLateboundVarSets = value;
  143. }
  144. }
  145. internal Dictionary<string, PythonVariable> Variables {
  146. get { return _variables; }
  147. }
  148. internal virtual bool IsGlobal {
  149. get { return false; }
  150. }
  151. internal virtual bool NeedsLocalContext {
  152. get {
  153. return NeedsLocalsDictionary || ContainsNestedFreeVariables;
  154. }
  155. }
  156. internal virtual string[] ParameterNames {
  157. get {
  158. return ArrayUtils.EmptyStrings;
  159. }
  160. }
  161. internal virtual int ArgCount {
  162. get {
  163. return 0;
  164. }
  165. }
  166. internal virtual FunctionAttributes Flags {
  167. get {
  168. return FunctionAttributes.None;
  169. }
  170. }
  171. internal abstract MSAst.LambdaExpression GetLambda();
  172. /// <summary>
  173. /// Gets or creates the FunctionCode object for this FunctionDefinition.
  174. /// </summary>
  175. internal FunctionCode GetOrMakeFunctionCode() {
  176. if (_funcCode == null) {
  177. _funcCode = new FunctionCode(GlobalParent.PyContext, OriginalDelegate, this, ScopeDocumentation);
  178. }
  179. return _funcCode;
  180. }
  181. internal virtual string ScopeDocumentation {
  182. get {
  183. return null;
  184. }
  185. }
  186. internal virtual Delegate OriginalDelegate {
  187. get {
  188. return null;
  189. }
  190. }
  191. internal virtual IList<string> GetVarNames() {
  192. List<string> res = new List<string>();
  193. AppendVariables(res);
  194. return res;
  195. }
  196. internal void AddFreeVariable(PythonVariable variable, bool accessedInScope) {
  197. if (_freeVars == null) {
  198. _freeVars = new List<PythonVariable>();
  199. }
  200. if(!_freeVars.Contains(variable)) {
  201. _freeVars.Add(variable);
  202. }
  203. }
  204. internal bool ShouldInterpret {
  205. get {
  206. if (_forceCompile) {
  207. return false;
  208. } else if (GlobalParent.CompilationMode == CompilationMode.Lookup) {
  209. return false; // ??? should be true?
  210. }
  211. CompilerContext context = GlobalParent.CompilerContext;
  212. return ((PythonContext)context.SourceUnit.LanguageContext).ShouldInterpret((PythonCompilerOptions)context.Options, context.SourceUnit);
  213. }
  214. set {
  215. _forceCompile = !value;
  216. }
  217. }
  218. internal string AddReferencedGlobal(string name) {
  219. if (_globalVars == null) {
  220. _globalVars = new List<string>();
  221. }
  222. if (!_globalVars.Contains(name)) {
  223. _globalVars.Add(name);
  224. }
  225. return name;
  226. }
  227. internal void AddCellVariable(PythonVariable variable) {
  228. if (_cellVars == null) {
  229. _cellVars = new List<string>();
  230. }
  231. if (!_cellVars.Contains(variable.Name)) {
  232. _cellVars.Add(variable.Name);
  233. }
  234. }
  235. internal List<string> AppendVariables(List<string> res) {
  236. if (Variables != null) {
  237. foreach (var variable in Variables) {
  238. if (variable.Value.Kind != VariableKind.Local) {
  239. continue;
  240. }
  241. if (CellVariables == null || !CellVariables.Contains(variable.Key)) {
  242. res.Add(variable.Key);
  243. }
  244. }
  245. }
  246. return res;
  247. }
  248. /// <summary>
  249. /// Variables that are bound in an outer scope - but not a global scope
  250. /// </summary>
  251. internal IList<PythonVariable> FreeVariables {
  252. get {
  253. return _freeVars;
  254. }
  255. }
  256. /// <summary>
  257. /// Variables that are bound to the global scope
  258. /// </summary>
  259. internal IList<string> GlobalVariables {
  260. get {
  261. return _globalVars;
  262. }
  263. }
  264. /// <summary>
  265. /// Variables that are referred to from a nested scope and need to be
  266. /// promoted to cells.
  267. /// </summary>
  268. internal IList<string> CellVariables {
  269. get {
  270. return _cellVars;
  271. }
  272. }
  273. internal Type GetClosureTupleType() {
  274. if (TupleCells > 0) {
  275. Type[] args = new Type[TupleCells];
  276. for (int i = 0; i < TupleCells; i++) {
  277. args[i] = typeof(ClosureCell);
  278. }
  279. return MutableTuple.MakeTupleType(args);
  280. }
  281. return null;
  282. }
  283. internal virtual int TupleCells {
  284. get {
  285. if (_closureVariables == null) {
  286. return 0;
  287. }
  288. return _closureVariables.Length;
  289. }
  290. }
  291. internal abstract bool ExposesLocalVariable(PythonVariable variable);
  292. internal virtual MSAst.Expression GetParentClosureTuple() {
  293. // PythonAst will never call this.
  294. throw new NotSupportedException();
  295. }
  296. private bool TryGetAnyVariable(string name, out PythonVariable variable) {
  297. if (_variables != null) {
  298. return _variables.TryGetValue(name, out variable);
  299. } else {
  300. variable = null;
  301. return false;
  302. }
  303. }
  304. internal bool TryGetVariable(string name, out PythonVariable variable) {
  305. if (TryGetAnyVariable(name, out variable)) {
  306. return true;
  307. } else {
  308. variable = null;
  309. return false;
  310. }
  311. }
  312. internal virtual bool TryBindOuter(ScopeStatement from, PythonReference reference, out PythonVariable variable) {
  313. // Hide scope contents by default (only functions expose their locals)
  314. variable = null;
  315. return false;
  316. }
  317. internal abstract PythonVariable BindReference(PythonNameBinder binder, PythonReference reference);
  318. internal virtual void Bind(PythonNameBinder binder) {
  319. if (_references != null) {
  320. foreach (var reference in _references.Values) {
  321. PythonVariable variable;
  322. reference.PythonVariable = variable = BindReference(binder, reference);
  323. // Accessing outer scope variable which is being deleted?
  324. if (variable != null) {
  325. if (variable.Deleted && variable.Scope != this && !variable.Scope.IsGlobal) {
  326. // report syntax error
  327. binder.ReportSyntaxError(
  328. String.Format(
  329. System.Globalization.CultureInfo.InvariantCulture,
  330. "can not delete variable '{0}' referenced in nested scope",
  331. reference.Name
  332. ),
  333. this);
  334. }
  335. }
  336. }
  337. }
  338. }
  339. internal virtual void FinishBind(PythonNameBinder binder) {
  340. List<ClosureInfo> closureVariables = null;
  341. if (FreeVariables != null && FreeVariables.Count > 0) {
  342. _localParentTuple = Ast.Parameter(Parent.GetClosureTupleType(), "$tuple");
  343. foreach (var variable in _freeVars) {
  344. var parentClosure = Parent._closureVariables;
  345. Debug.Assert(parentClosure != null);
  346. for (int i = 0; i < parentClosure.Length; i++) {
  347. if (parentClosure[i].Variable == variable) {
  348. _variableMapping[variable] = new ClosureExpression(variable, Ast.Property(_localParentTuple, String.Format("Item{0:D3}", i)), null);
  349. break;
  350. }
  351. }
  352. Debug.Assert(_variableMapping.ContainsKey(variable));
  353. if (closureVariables == null) {
  354. closureVariables = new List<ClosureInfo>();
  355. }
  356. closureVariables.Add(new ClosureInfo(variable, !(this is ClassDefinition)));
  357. }
  358. }
  359. if (Variables != null) {
  360. foreach (PythonVariable variable in Variables.Values) {
  361. if (!HasClosureVariable(closureVariables, variable) &&
  362. !variable.IsGlobal && (variable.AccessedInNestedScope || ExposesLocalVariable(variable))) {
  363. if (closureVariables == null) {
  364. closureVariables = new List<ClosureInfo>();
  365. }
  366. closureVariables.Add(new ClosureInfo(variable, true));
  367. }
  368. if (variable.Kind == VariableKind.Local) {
  369. Debug.Assert(variable.Scope == this);
  370. if (variable.AccessedInNestedScope || ExposesLocalVariable(variable)) {
  371. _variableMapping[variable] = new ClosureExpression(variable, Ast.Parameter(typeof(ClosureCell), variable.Name), null);
  372. } else {
  373. _variableMapping[variable] = Ast.Parameter(typeof(object), variable.Name);
  374. }
  375. }
  376. }
  377. }
  378. if (closureVariables != null) {
  379. _closureVariables = closureVariables.ToArray();
  380. }
  381. // no longer needed
  382. _references = null;
  383. }
  384. private static bool HasClosureVariable(List<ClosureInfo> closureVariables, PythonVariable variable) {
  385. if (closureVariables == null) {
  386. return false;
  387. }
  388. for (int i = 0; i < closureVariables.Count; i++) {
  389. if (closureVariables[i].Variable == variable) {
  390. return true;
  391. }
  392. }
  393. return false;
  394. }
  395. private void EnsureVariables() {
  396. if (_variables == null) {
  397. _variables = new Dictionary<string, PythonVariable>(StringComparer.Ordinal);
  398. }
  399. }
  400. internal void AddGlobalVariable(PythonVariable variable) {
  401. EnsureVariables();
  402. _variables[variable.Name] = variable;
  403. }
  404. internal PythonReference Reference(string name) {
  405. if (_references == null) {
  406. _references = new Dictionary<string, PythonReference>(StringComparer.Ordinal);
  407. }
  408. PythonReference reference;
  409. if (!_references.TryGetValue(name, out reference)) {
  410. _references[name] = reference = new PythonReference(name);
  411. }
  412. return reference;
  413. }
  414. internal bool IsReferenced(string name) {
  415. PythonReference reference;
  416. return _references != null && _references.TryGetValue(name, out reference);
  417. }
  418. internal PythonVariable/*!*/ CreateVariable(string name, VariableKind kind) {
  419. EnsureVariables();
  420. Debug.Assert(!_variables.ContainsKey(name));
  421. PythonVariable variable;
  422. _variables[name] = variable = new PythonVariable(name, kind, this);
  423. return variable;
  424. }
  425. internal PythonVariable/*!*/ EnsureVariable(string name) {
  426. PythonVariable variable;
  427. if (!TryGetVariable(name, out variable)) {
  428. return CreateVariable(name, VariableKind.Local);
  429. }
  430. return variable;
  431. }
  432. internal PythonVariable DefineParameter(string name) {
  433. return CreateVariable(name, VariableKind.Parameter);
  434. }
  435. internal PythonContext PyContext {
  436. get {
  437. return (PythonContext)GlobalParent.CompilerContext.SourceUnit.LanguageContext;
  438. }
  439. }
  440. #region Debug Info Tracking
  441. private MSAst.SymbolDocumentInfo Document {
  442. get {
  443. return GlobalParent.Document;
  444. }
  445. }
  446. internal MSAst.Expression/*!*/ AddDebugInfo(MSAst.Expression/*!*/ expression, SourceLocation start, SourceLocation end) {
  447. if (PyContext.PythonOptions.GCStress != null) {
  448. expression = Ast.Block(
  449. Ast.Call(
  450. typeof(GC).GetMethod("Collect", new[] { typeof(int) }),
  451. Ast.Constant(PyContext.PythonOptions.GCStress.Value)
  452. ),
  453. expression
  454. );
  455. }
  456. return AstUtils.AddDebugInfo(expression, Document, start, end);
  457. }
  458. internal MSAst.Expression/*!*/ AddDebugInfo(MSAst.Expression/*!*/ expression, SourceSpan location) {
  459. return AddDebugInfo(expression, location.Start, location.End);
  460. }
  461. internal MSAst.Expression/*!*/ AddDebugInfoAndVoid(MSAst.Expression/*!*/ expression, SourceSpan location) {
  462. if (expression.Type != typeof(void)) {
  463. expression = AstUtils.Void(expression);
  464. }
  465. return AddDebugInfo(expression, location);
  466. }
  467. #endregion
  468. #region Runtime Line Number Tracing
  469. /// <summary>
  470. /// Gets the expression for updating the dynamic stack trace at runtime when an
  471. /// exception is thrown.
  472. /// </summary>
  473. internal MSAst.Expression GetUpdateTrackbackExpression() {
  474. if (!_containsExceptionHandling) {
  475. Debug.Assert(Name != null);
  476. return Ast.Call(
  477. AstMethods.UpdateStackTrace,
  478. LocalContext,
  479. _funcCodeExpr,
  480. _GetCurrentMethod,
  481. AstUtils.Constant(Name),
  482. AstUtils.Constant(GlobalParent.SourceUnit.Path ?? "<string>"),
  483. new LastFaultingLineExpression(LineNumberExpression)
  484. );
  485. }
  486. return GetSaveLineNumberExpression(true);
  487. }
  488. /// <summary>
  489. /// Gets the expression for the actual updating of the line number for stack traces to be available
  490. /// </summary>
  491. internal MSAst.Expression GetSaveLineNumberExpression(bool preventAdditionalAdds) {
  492. MSAst.Expression res;
  493. if (preventAdditionalAdds) {
  494. res = _saveLineNumberNoAdds;
  495. } else {
  496. res = _saveLineNumberAdds;
  497. }
  498. if (res == null) {
  499. res = Ast.Block(
  500. AstUtils.If(
  501. Ast.Not(
  502. LineNumberUpdated
  503. ),
  504. Ast.Call(
  505. AstMethods.UpdateStackTrace,
  506. LocalContext,
  507. _funcCodeExpr,
  508. _GetCurrentMethod,
  509. AstUtils.Constant(Name),
  510. AstUtils.Constant(GlobalParent.SourceUnit.Path ?? "<string>"),
  511. new LastFaultingLineExpression(LineNumberExpression)
  512. )
  513. ),
  514. Ast.Assign(
  515. LineNumberUpdated,
  516. AstUtils.Constant(preventAdditionalAdds)
  517. ),
  518. AstUtils.Empty()
  519. );
  520. if (preventAdditionalAdds) {
  521. _saveLineNumberNoAdds = res;
  522. } else {
  523. _saveLineNumberAdds = res;
  524. }
  525. }
  526. return res;
  527. }
  528. /// <summary>
  529. /// Wraps the body of a statement which should result in a frame being available during
  530. /// exception handling. This ensures the line number is updated as the stack is unwound.
  531. /// </summary>
  532. internal MSAst.Expression/*!*/ WrapScopeStatements(MSAst.Expression/*!*/ body, bool canThrow) {
  533. if (canThrow) {
  534. body = Ast.Block(
  535. new[] { LineNumberExpression, LineNumberUpdated },
  536. AstUtils.Try(
  537. body
  538. ).Fault(
  539. GetUpdateTrackbackExpression()
  540. )
  541. );
  542. }
  543. return body;
  544. }
  545. #endregion
  546. /// <summary>
  547. /// Provides a place holder for the expression which represents
  548. /// a FunctionCode. For functions/classes this gets updated after
  549. /// the AST has been generated because the FunctionCode needs to
  550. /// know about the tree which gets generated. For modules we
  551. /// immediately have the value because it always comes in as a parameter.
  552. /// </summary>
  553. class DelayedFunctionCode : MSAst.Expression {
  554. private MSAst.Expression _funcCode;
  555. public override bool CanReduce {
  556. get {
  557. return true;
  558. }
  559. }
  560. public MSAst.Expression Code {
  561. get {
  562. return _funcCode;
  563. }
  564. set {
  565. _funcCode = value;
  566. }
  567. }
  568. public override Type Type {
  569. get {
  570. return typeof(FunctionCode);
  571. }
  572. }
  573. protected override MSAst.Expression VisitChildren(MSAst.ExpressionVisitor visitor) {
  574. if (_funcCode != null) {
  575. MSAst.Expression funcCode = visitor.Visit(_funcCode);
  576. if (funcCode != _funcCode) {
  577. DelayedFunctionCode res = new DelayedFunctionCode();
  578. res._funcCode = funcCode;
  579. return res;
  580. }
  581. }
  582. return this;
  583. }
  584. public override MSAst.Expression Reduce() {
  585. Debug.Assert(_funcCode != null);
  586. return _funcCode;
  587. }
  588. public override MSAst.ExpressionType NodeType {
  589. get {
  590. return MSAst.ExpressionType.Extension;
  591. }
  592. }
  593. }
  594. internal MSAst.Expression FuncCodeExpr {
  595. get {
  596. return _funcCodeExpr.Code;
  597. }
  598. set {
  599. _funcCodeExpr.Code = value;
  600. }
  601. }
  602. internal MSAst.MethodCallExpression CreateLocalContext(MSAst.Expression parentContext) {
  603. var closureVariables = _closureVariables;
  604. if (_closureVariables == null) {
  605. closureVariables = new ClosureInfo[0];
  606. }
  607. return Ast.Call(
  608. AstMethods.CreateLocalContext,
  609. parentContext,
  610. MutableTuple.Create(ArrayUtils.ConvertAll(closureVariables, x => GetClosureCell(x))),
  611. Ast.Constant(ArrayUtils.ConvertAll(closureVariables, x => x.AccessedInScope ? x.Variable.Name : null))
  612. );
  613. }
  614. private MSAst.Expression GetClosureCell(ClosureInfo variable) {
  615. return ((ClosureExpression)GetVariableExpression(variable.Variable)).ClosureCell;
  616. }
  617. internal MSAst.Expression GetVariableExpression(PythonVariable variable) {
  618. if (variable.IsGlobal) {
  619. return GlobalParent.ModuleVariables[variable];
  620. }
  621. Debug.Assert(_variableMapping.ContainsKey(variable));
  622. return _variableMapping[variable];
  623. }
  624. internal void CreateVariables(ReadOnlyCollectionBuilder<MSAst.ParameterExpression> locals, List<MSAst.Expression> init) {
  625. if (Variables != null) {
  626. foreach (PythonVariable variable in Variables.Values) {
  627. if(variable.Kind != VariableKind.Global) {
  628. ClosureExpression closure = GetVariableExpression(variable) as ClosureExpression;
  629. if (closure != null) {
  630. init.Add(closure.Create());
  631. locals.Add((MSAst.ParameterExpression)closure.ClosureCell);
  632. } else if (variable.Kind == VariableKind.Local) {
  633. locals.Add((MSAst.ParameterExpression)GetVariableExpression(variable));
  634. if (variable.ReadBeforeInitialized) {
  635. init.Add(
  636. AssignValue(
  637. GetVariableExpression(variable),
  638. MSAst.Expression.Field(null, typeof(Uninitialized).GetField("Instance"))
  639. )
  640. );
  641. }
  642. }
  643. }
  644. }
  645. }
  646. if (IsClosure) {
  647. Type tupleType = Parent.GetClosureTupleType();
  648. Debug.Assert(tupleType != null);
  649. init.Add(
  650. MSAst.Expression.Assign(
  651. LocalParentTuple,
  652. MSAst.Expression.Convert(
  653. GetParentClosureTuple(),
  654. tupleType
  655. )
  656. )
  657. );
  658. locals.Add(LocalParentTuple);
  659. }
  660. }
  661. internal MSAst.Expression AddDecorators(MSAst.Expression ret, IList<Expression> decorators) {
  662. // add decorators
  663. if (decorators != null) {
  664. for (int i = decorators.Count - 1; i >= 0; i--) {
  665. Expression decorator = decorators[i];
  666. ret = Parent.Invoke(
  667. new CallSignature(1),
  668. Parent.LocalContext,
  669. decorator,
  670. ret
  671. );
  672. }
  673. }
  674. return ret;
  675. }
  676. internal MSAst.Expression/*!*/ Invoke(CallSignature signature, params MSAst.Expression/*!*/[]/*!*/ args) {
  677. PythonInvokeBinder invoke = PyContext.Invoke(signature);
  678. switch (args.Length) {
  679. case 1: return GlobalParent.CompilationMode.Dynamic(invoke, typeof(object), args[0]);
  680. case 2: return GlobalParent.CompilationMode.Dynamic(invoke, typeof(object), args[0], args[1]);
  681. case 3: return GlobalParent.CompilationMode.Dynamic(invoke, typeof(object), args[0], args[1], args[2]);
  682. case 4: return GlobalParent.CompilationMode.Dynamic(invoke, typeof(object), args[0], args[1], args[2], args[3]);
  683. default:
  684. return GlobalParent.CompilationMode.Dynamic(
  685. invoke,
  686. typeof(object),
  687. args
  688. );
  689. }
  690. }
  691. internal ScopeStatement CopyForRewrite() {
  692. return (ScopeStatement)MemberwiseClone();
  693. }
  694. internal virtual void RewriteBody(PythonAst.LookupVisitor visitor) {
  695. _funcCode = null;
  696. }
  697. struct ClosureInfo {
  698. public PythonVariable Variable;
  699. public bool AccessedInScope;
  700. public ClosureInfo(PythonVariable variable, bool accessedInScope) {
  701. Variable = variable;
  702. AccessedInScope = accessedInScope;
  703. }
  704. }
  705. internal virtual bool PrintExpressions {
  706. get {
  707. return false;
  708. }
  709. }
  710. #region Profiling Support
  711. internal virtual string ProfilerName {
  712. get {
  713. return Name;
  714. }
  715. }
  716. /// <summary>
  717. /// Reducible node so that re-writing for profiling does not occur until
  718. /// after the script code has been completed and is ready to be compiled.
  719. ///
  720. /// Without this extra node profiling would force reduction of the node
  721. /// and we wouldn't have setup our constant access correctly yet.
  722. /// </summary>
  723. class DelayedProfiling : MSAst.Expression {
  724. private readonly ScopeStatement _ast;
  725. private readonly MSAst.Expression _body;
  726. private readonly MSAst.ParameterExpression _tick;
  727. public DelayedProfiling(ScopeStatement ast, MSAst.Expression body, MSAst.ParameterExpression tick) {
  728. _ast = ast;
  729. _body = body;
  730. _tick = tick;
  731. }
  732. public override bool CanReduce {
  733. get {
  734. return true;
  735. }
  736. }
  737. public override Type Type {
  738. get {
  739. return _body.Type;
  740. }
  741. }
  742. protected override MSAst.Expression VisitChildren(MSAst.ExpressionVisitor visitor) {
  743. return visitor.Visit(_body);
  744. }
  745. public override MSAst.Expression Reduce() {
  746. string profilerName = _ast.ProfilerName;
  747. bool unique = (profilerName == NameForExec);
  748. return Ast.Block(
  749. new[] { _tick },
  750. _ast.GlobalParent._profiler.AddProfiling(_body, _tick, profilerName, unique)
  751. );
  752. }
  753. public override MSAst.ExpressionType NodeType {
  754. get {
  755. return MSAst.ExpressionType.Extension;
  756. }
  757. }
  758. }
  759. internal MSAst.Expression AddProfiling(MSAst.Expression/*!*/ body) {
  760. if (GlobalParent._profiler != null) {
  761. MSAst.ParameterExpression tick = Ast.Variable(typeof(long), "$tick");
  762. return new DelayedProfiling(this, body, tick);
  763. }
  764. return body;
  765. }
  766. #endregion
  767. }
  768. }