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

/Languages/IronPython/IronPython/Compiler/Ast/ScopeStatement.cs

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