PageRenderTime 65ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/Backend/AST/Statement.cs

https://bitbucket.org/AdamMil/boaold
C# | 1728 lines | 1470 code | 215 blank | 43 comment | 333 complexity | 29231b00b8989c2e303b77271fd8c4f1 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Boa is the reference implementation for a language similar to Python,
  3. also called Boa. This implementation is both interpreted and compiled,
  4. targeting the Microsoft .NET Framework.
  5. http://www.adammil.net/
  6. Copyright (C) 2004-2005 Adam Milazzo
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. using System;
  20. using System.Collections;
  21. using System.Collections.Specialized;
  22. using System.Reflection;
  23. using System.Reflection.Emit;
  24. using Boa.Runtime;
  25. namespace Boa.AST
  26. {
  27. // TODO: possibly rework compiled closures
  28. // TODO: add versions optimized for System.Array?
  29. // TODO: disallow 'yield' and 'return' outside of functions
  30. /* TODO:
  31. If a variable is referenced in an enclosing scope, it is illegal
  32. to delete the name. An error will be reported at compile time.
  33. If the wild card form of import -- "import *" -- is used in a function and the function
  34. contains or is a nested block with free variables, the compiler will raise a SyntaxError.
  35. If exec is used in a function and the function contains or is a nested block with free
  36. variables, the compiler will raise a SyntaxError unless the exec explicitly specifies the local
  37. namespace for the exec. (In other words, "exec obj" would be illegal, but "exec obj in ns" would be legal.)
  38. */
  39. // TODO: make sure all enumerators can handle the underlying collection being changed, if possible
  40. // TODO: disallow 'break' and 'continue' inside 'finally' blocks (difficult to implement)
  41. // TODO: allow 'from xxx import yyy/*' inside functions/class defs
  42. // TODO: using exceptions is very slow
  43. #region Exceptions (used to aid implementation)
  44. public class BreakException : Exception
  45. { public BreakException() { }
  46. public BreakException(string name) { Name=name; }
  47. public string Name;
  48. public static BreakException Value = new BreakException();
  49. }
  50. public class ContinueException : Exception
  51. { public ContinueException() { }
  52. public ContinueException(string name) { Name=name; }
  53. public string Name;
  54. public static ContinueException Value = new ContinueException();
  55. }
  56. public class ReturnException : Exception
  57. { public ReturnException(object value) { Value=value; }
  58. public object Value;
  59. }
  60. #endregion
  61. #region Walkers
  62. #region JumpFinder
  63. sealed class JumpFinder : IWalker
  64. { public JumpFinder(string name, Label start, Label end) { this.name=name; this.start=start; this.end=end; }
  65. public void PostWalk(Node node)
  66. { if(node is ExceptionStatement) inTry--;
  67. }
  68. public bool Walk(Node node)
  69. { if(node is BreakStatement)
  70. { BreakStatement bs = (BreakStatement)node;
  71. if(bs.Name==name)
  72. { bs.Label = end;
  73. bs.NeedsLeave = InTry;
  74. }
  75. }
  76. else if(node is ContinueStatement)
  77. { ContinueStatement cs = (ContinueStatement)node;
  78. if(cs.Name==name)
  79. { cs.Label = start;
  80. cs.NeedsLeave = InTry;
  81. }
  82. }
  83. else if(name==null && (node is WhileStatement || node is ForStatement) || node is DefStatement) return false;
  84. else if(node is ExceptionStatement) inTry++;
  85. return true;
  86. }
  87. bool InTry { get { return inTry>0; } }
  88. Label start, end;
  89. string name;
  90. int inTry;
  91. }
  92. #endregion
  93. #region NameFinder
  94. sealed class NameFinder : IWalker
  95. { public static Name[] Find(Node n)
  96. { NameFinder nf = new NameFinder();
  97. n.Walk(nf);
  98. return (Name[])nf.names.ToArray(typeof(Name));
  99. }
  100. public void PostWalk(Node n) { }
  101. public bool Walk(Node n)
  102. { if(n is NameExpression) names.Add(((NameExpression)n).Name);
  103. return true;
  104. }
  105. ArrayList names = new ArrayList();
  106. }
  107. #endregion
  108. #region Optimizer
  109. sealed class Optimizer : IWalker
  110. { public void PostWalk(Node n) { n.Optimize(); }
  111. public bool Walk(Node n) { return true; }
  112. }
  113. #endregion
  114. #endregion
  115. #region Statement
  116. public abstract class Statement : Node
  117. { public abstract void Emit(CodeGenerator cg);
  118. public abstract void Execute(Frame frame);
  119. public void PostProcessForCompile()
  120. { PostProcess();
  121. Walk(new NameDecorator());
  122. }
  123. public void PostProcessForInterpret() { PostProcess(); }
  124. void PostProcess()
  125. { Walk(new JumpChecker());
  126. Walk(new TryChecker());
  127. if(Options.Optimize) Walk(new Optimizer());
  128. }
  129. #region JumpChecker
  130. sealed class JumpChecker : IWalker
  131. { public void PostWalk(Node node)
  132. { if(node is Suite)
  133. { if(((Suite)node).Name!=null) blocks.RemoveAt(blocks.Count-1);
  134. }
  135. else if(node is WhileStatement || node is ForStatement) blocks.RemoveAt(blocks.Count-1);
  136. else if(node is DefStatement)
  137. { if(blocks!=null)
  138. { blocks.Clear();
  139. if(flist!=null) flist = new Stack();
  140. flist.Push(blocks);
  141. blocks = (ArrayList)lists.Pop();
  142. }
  143. }
  144. }
  145. public bool Walk(Node node)
  146. { if(node is Suite)
  147. { if(((Suite)node).Name!=null)
  148. { if(blocks==null) blocks = new ArrayList();
  149. blocks.Add(node);
  150. }
  151. }
  152. else if(node is WhileStatement || node is ForStatement)
  153. { if(blocks==null) blocks = new ArrayList();
  154. blocks.Add(node);
  155. }
  156. else if(node is JumpStatement)
  157. { string name = ((JumpStatement)node).Name;
  158. if(name!=null)
  159. { if(blocks!=null)
  160. foreach(object n in blocks)
  161. if(n is Suite && ((Suite)n).Name==name) return false;
  162. Ops.SyntaxError(node, "break/continue: unable to find a valid jump target named '{0}'", name);
  163. }
  164. else
  165. { if(blocks!=null)
  166. for(int i=blocks.Count-1; i>=0; i--)
  167. if(blocks[i] is WhileStatement || blocks[i] is ForStatement) return false;
  168. Ops.SyntaxError(node, "break/continue: unable to find a valid enclosing loop");
  169. }
  170. }
  171. else if(node is DefStatement)
  172. { if(lists==null) lists = new Stack();
  173. lists.Push(blocks);
  174. blocks = flist==null || flist.Count==0 ? null : (ArrayList)flist.Pop();
  175. }
  176. return true;
  177. }
  178. ArrayList blocks;
  179. Stack lists, flist;
  180. }
  181. #endregion
  182. #region NameDecorator
  183. sealed class NameDecorator : IWalker
  184. { public NameDecorator() { }
  185. NameDecorator(SortedList names) { parentNames=names; }
  186. public void PostWalk(Node node)
  187. { if(node==current)
  188. { inDef=false;
  189. ArrayList inherit = innerFuncs.Count==0 ? null : new ArrayList();
  190. foreach(BoaFunction func in innerFuncs)
  191. { NameDecorator dec = new NameDecorator(names);
  192. func.Walk(dec);
  193. foreach(Name dname in dec.names.Values)
  194. if(dname.Scope==Scope.Free)
  195. { Name name = (Name)names[dname.String];
  196. if(name==null) names[dname.String] = dname;
  197. else if(name.Scope==Scope.Local) inherit.Add(name);
  198. }
  199. if(inherit.Count>0)
  200. { func.Inherit = (Name[])inherit.ToArray(typeof(Name));
  201. inherit.Clear();
  202. }
  203. }
  204. }
  205. }
  206. public bool Walk(Node node)
  207. { while(node is ParenExpression) node = ((ParenExpression)node).Expression;
  208. if(inDef)
  209. { if(node is BoaFunction)
  210. { BoaFunction fun = (BoaFunction)node;
  211. innerFuncs.Add(fun);
  212. if(fun.Name!=null)
  213. { fun.Name = AddName(fun.Name);
  214. fun.Name.Scope = Scope.Local;
  215. }
  216. for(int i=0; i<fun.Parameters.Length; i++)
  217. if(fun.Parameters[i].Default!=null) fun.Parameters[i].Default.Walk(this);
  218. return false;
  219. }
  220. else if(node is AssignStatement)
  221. foreach(Expression e in ((AssignStatement)node).LHS) HandleAssignment(e);
  222. else if(node is ForStatement) HandleAssignment(((ForStatement)node).Names);
  223. else if(node is ListCompExpression)
  224. foreach(ListCompFor f in ((ListCompExpression)node).Fors) HandleAssignment(f.Names);
  225. else if(node is ExceptionStatement)
  226. { foreach(ExceptClause ec in ((ExceptionStatement)node).Except)
  227. if(ec.Target!=null) HandleAssignment(ec.Target);
  228. }
  229. else if(node is ImportStatement)
  230. { ImportStatement imp = (ImportStatement)node;
  231. foreach(ImportName n in imp.Names) AddName(new Name(n.AsName==null ? n.SlotName : n.AsName, Scope.Local));
  232. }
  233. else if(node is ImportFromStatement)
  234. { ImportFromStatement imp = (ImportFromStatement)node;
  235. if(imp.Names[0].Name=="*") // TODO: perhaps this should be disallowed within other contexts as well
  236. Ops.SyntaxError(node, "'from ... import *' is disallowed within function definitions");
  237. foreach(ImportName n in imp.Names) AddName(new Name(n.AsName==null ? n.Name : n.AsName, Scope.Local));
  238. }
  239. else if(node is NameExpression)
  240. { NameExpression ne = (NameExpression)node;
  241. ne.Name = AddName(ne.Name);
  242. }
  243. }
  244. else if(node is BoaFunction)
  245. { if(innerFuncs==null)
  246. { innerFuncs = new ArrayList();
  247. names = new SortedList();
  248. }
  249. BoaFunction func = (BoaFunction)node;
  250. foreach(Parameter p in func.Parameters)
  251. { if(func.Globals!=null)
  252. for(int i=0; i<func.Globals.Length; i++)
  253. if(func.Globals[i].String==p.Name.String)
  254. throw Ops.SyntaxError(node, "'{0}' is both local and global", p.Name.String);
  255. names[p.Name.String] = p.Name;
  256. }
  257. current=func; inDef=true;
  258. }
  259. return true;
  260. }
  261. Name AddName(Name name)
  262. { Name lname = (Name)names[name.String];
  263. if(lname==null)
  264. { names[name.String] = lname = name;
  265. if(current.Globals!=null)
  266. for(int i=0; i<current.Globals.Length; i++)
  267. if(current.Globals[i].String==name.String)
  268. { name.Scope = Scope.Global;
  269. break;
  270. }
  271. }
  272. return lname;
  273. }
  274. void HandleAssignment(Expression assignedTo)
  275. { while(assignedTo is ParenExpression) assignedTo = ((ParenExpression)assignedTo).Expression;
  276. if(assignedTo is NameExpression)
  277. { NameExpression ne = (NameExpression)assignedTo;
  278. ne.Name = AddName(ne.Name);
  279. if(ne.Name.Scope==Scope.Free && (parentNames==null || parentNames[ne.Name.String]==null))
  280. ne.Name.Scope=Scope.Local;
  281. }
  282. else if(assignedTo is TupleExpression)
  283. foreach(Expression e in ((TupleExpression)assignedTo).Expressions) HandleAssignment(e);
  284. }
  285. BoaFunction current;
  286. ArrayList innerFuncs;
  287. SortedList names, parentNames;
  288. bool inDef;
  289. }
  290. #endregion
  291. #region TryChecker
  292. sealed class TryChecker : IWalker // checks for exceptionless 'raise' outside of a try statement
  293. { public void PostWalk(Node node) { }
  294. public bool Walk(Node node)
  295. { if(inTry)
  296. { if(node is TryStatement)
  297. { if(nested==null) nested = new ArrayList();
  298. nested.Add(node);
  299. }
  300. return true;
  301. }
  302. else if(node is TryStatement)
  303. { TryStatement ts = (TryStatement)node;
  304. ts.Body.Walk(this);
  305. if(ts.Else!=null) ts.Else.Walk(this);
  306. if(ts.Finally!=null) ts.Finally.Walk(this);
  307. inTry = true;
  308. foreach(ExceptClause ec in ts.Except) ec.Body.Walk(this);
  309. inTry = false;
  310. if(nested!=null && nested.Count>0)
  311. { TryStatement[] nest = (TryStatement[])nested.ToArray(typeof(TryStatement));
  312. nested.Clear();
  313. foreach(TryStatement nts in nest) nts.Walk(this);
  314. }
  315. return false;
  316. }
  317. else if(node is RaiseStatement)
  318. { if(((RaiseStatement)node).Expression==null)
  319. throw Ops.SyntaxError(node, "expression-less 'raise' can only occur inside 'except' block");
  320. }
  321. else return true;
  322. return false;
  323. }
  324. ArrayList nested;
  325. bool inTry;
  326. }
  327. #endregion
  328. }
  329. #endregion
  330. #region AssertStatement
  331. public class AssertStatement : Statement
  332. { public AssertStatement(Expression e) { Expression=e; }
  333. public override void Emit(CodeGenerator cg)
  334. { if(Options.Debug)
  335. { Label good = cg.ILG.DefineLabel();
  336. Expression.Emit(cg);
  337. cg.EmitCall(typeof(Ops), "IsTrue");
  338. cg.ILG.Emit(OpCodes.Brtrue, good);
  339. cg.EmitString("assertion failed: ");
  340. cg.EmitString(Expression.ToCode());
  341. cg.EmitCall(typeof(string), "Concat", new Type[] { typeof(string), typeof(string) });
  342. cg.EmitNew(typeof(AssertionErrorException), new Type[] { typeof(string) });
  343. cg.ILG.Emit(OpCodes.Throw);
  344. cg.ILG.MarkLabel(good);
  345. }
  346. }
  347. public override void Execute(Frame frame)
  348. { if(Options.Debug && !Ops.IsTrue(Expression.Evaluate(frame)))
  349. throw Ops.AssertionError(this, "assertion failed: "+Expression.ToCode());
  350. }
  351. public override void ToCode(System.Text.StringBuilder sb, int indent)
  352. { sb.Append("assert ");
  353. Expression.ToCode(sb, 0);
  354. sb.Append('\n');
  355. }
  356. public override void Walk(IWalker w)
  357. { if(w.Walk(this)) Expression.Walk(w);
  358. w.PostWalk(this);
  359. }
  360. public Expression Expression;
  361. }
  362. #endregion
  363. // FIXME: make this work: ((a,b)) = ((1,2))
  364. #region AssignStatement
  365. public class AssignStatement : Statement
  366. { public AssignStatement() { }
  367. public AssignStatement(Expression lhs) { LHS=new Expression[] { lhs }; }
  368. public AssignStatement(Expression lhs, Expression rhs) : this(lhs) { RHS=rhs; }
  369. public AssignStatement(Expression[] lhs, Expression rhs) { LHS=lhs; RHS=rhs; }
  370. public override void Emit(CodeGenerator cg)
  371. { if(Op!=null)
  372. { new BinaryOpExpression(Op, LHS[0], RHS).Emit(cg);
  373. LHS[0].EmitSet(cg);
  374. return;
  375. }
  376. bool leftAllTups = RHS is TupleExpression;
  377. if(leftAllTups) foreach(Expression e in LHS) if(!(e is TupleExpression)) { leftAllTups=false; break; }
  378. if(leftAllTups) // RHS is TupleExpression
  379. { TupleExpression rhs = (TupleExpression)RHS;
  380. TupleExpression[] lhs = new TupleExpression[LHS.Length];
  381. for(int i=0; i<LHS.Length; i++)
  382. { lhs[i] = (TupleExpression)LHS[i];
  383. if(lhs[i].Expressions.Length != rhs.Expressions.Length)
  384. throw Ops.ValueError(this, "wrong number of values to unpack");
  385. }
  386. for(int i=0; i<rhs.Expressions.Length; i++) rhs.Expressions[i].Emit(cg);
  387. for(int i=rhs.Expressions.Length-1; i>=0; i--)
  388. for(int j=lhs.Length-1; j>=0; j--)
  389. { if(j!=0) cg.ILG.Emit(OpCodes.Dup);
  390. lhs[j].Expressions[i].EmitSet(cg);
  391. }
  392. }
  393. else
  394. { object value=null;
  395. bool emitted=true;
  396. if(RHS!=null)
  397. { if(RHS.IsConstant) { value=RHS.GetValue(); emitted=false; }
  398. else RHS.Emit(cg);
  399. }
  400. for(int ti=LHS.Length-1; ti>=0; ti--)
  401. { if(LHS[ti] is TupleExpression)
  402. { TupleExpression lhs = (TupleExpression)LHS[ti];
  403. if(IsConstant)
  404. { if(value is ISequence)
  405. { if(((ISequence)value).__len__() != lhs.Expressions.Length)
  406. throw Ops.ValueError(this, "wrong number of values to unpack");
  407. }
  408. else if(value is string)
  409. { if(((string)value).Length != lhs.Expressions.Length)
  410. throw Ops.ValueError(this, "wrong number of values to unpack");
  411. }
  412. else
  413. { object len;
  414. if(!Ops.TryInvoke(value, "__len__", out len))
  415. throw Ops.TypeError(this, "expecting a sequence on the right side of a tuple assignment");
  416. if(Ops.ToInt(len) != lhs.Expressions.Length)
  417. throw Ops.ValueError(this, "wrong number of values to unpack");
  418. }
  419. IEnumerator e = Ops.GetEnumerator(value);
  420. int i=0;
  421. while(e.MoveNext() && i<lhs.Expressions.Length)
  422. { cg.EmitConstant(e.Current);
  423. lhs.Expressions[i++].EmitSet(cg);
  424. }
  425. if(emitted && ti==0) cg.ILG.Emit(OpCodes.Pop);
  426. }
  427. else
  428. { if(!emitted) { RHS.Emit(cg); emitted=true; }
  429. if(ti!=0) cg.ILG.Emit(OpCodes.Dup);
  430. Slot eslot = cg.AllocLocalTemp(typeof(IEnumerator));
  431. cg.EmitInt(lhs.Expressions.Length);
  432. cg.EmitCall(typeof(Ops), "PrepareTupleAssignment");
  433. for(int i=0; i<lhs.Expressions.Length; i++)
  434. { if(i!=lhs.Expressions.Length-1) cg.ILG.Emit(OpCodes.Dup);
  435. cg.ILG.Emit(OpCodes.Dup);
  436. cg.EmitCall(typeof(IEnumerator), "MoveNext");
  437. cg.ILG.Emit(OpCodes.Pop); // ignore return value
  438. cg.EmitPropGet(typeof(IEnumerator), "Current");
  439. lhs.Expressions[i].EmitSet(cg);
  440. }
  441. cg.FreeLocalTemp(eslot);
  442. }
  443. }
  444. else
  445. { if(!emitted) { RHS.Emit(cg); emitted=true; }
  446. if(ti!=0) cg.ILG.Emit(OpCodes.Dup);
  447. LHS[ti].EmitSet(cg);
  448. }
  449. }
  450. }
  451. }
  452. public override void Execute(Frame frame)
  453. { if(Op!=null) LHS[0].Assign(new BinaryOpExpression(Op, LHS[0], RHS).Evaluate(frame), frame);
  454. else
  455. { object value = RHS.Evaluate(frame);
  456. for(int i=LHS.Length-1; i>=0; i--) LHS[i].Assign(value, frame);
  457. }
  458. }
  459. public override object GetValue() { return RHS.GetValue(); }
  460. public override void Optimize() { IsConstant = RHS!=null && RHS.IsConstant; }
  461. public override void ToCode(System.Text.StringBuilder sb, int indent)
  462. { foreach(Expression e in LHS)
  463. { e.ToCode(sb, 0);
  464. sb.Append(" = ");
  465. }
  466. RHS.ToCode(sb, 0);
  467. }
  468. public override void Walk(IWalker w)
  469. { if(w.Walk(this))
  470. { foreach(Expression e in LHS) e.Walk(w);
  471. RHS.Walk(w);
  472. }
  473. w.PostWalk(this);
  474. }
  475. public Expression[] LHS;
  476. public Expression RHS;
  477. public BinaryOperator Op;
  478. }
  479. #endregion
  480. #region BreakStatement
  481. public class BreakStatement : JumpStatement
  482. { public BreakStatement() { }
  483. public BreakStatement(string name) : base(name) { }
  484. public override void Execute(Frame frame)
  485. { throw Name==null ? BreakException.Value : new BreakException(Name);
  486. }
  487. public override void ToCode(System.Text.StringBuilder sb, int indent)
  488. { sb.Append("break");
  489. if(Name!=null) sb.Append(' ').Append(Name);
  490. }
  491. }
  492. #endregion
  493. // TODO: http://www.python.org/2.2.3/descrintro.html#metaclasses
  494. #region ClassStatement
  495. public class ClassStatement : Statement
  496. { public ClassStatement(string name, Expression[] bases, Statement body)
  497. { Name = new Name(name);
  498. Bases = bases;
  499. Body = body;
  500. docstring = Misc.BodyToDocString(body);
  501. }
  502. public override void Emit(CodeGenerator cg)
  503. { bool interactive = Options.Interactive;
  504. Options.Interactive = false;
  505. try
  506. { CodeGenerator icg = cg.TypeGenerator.DefineMethod(Name.String+"$maker"+Misc.NextIndex,
  507. typeof(IDictionary), Type.EmptyTypes);
  508. LocalNamespace ns = new LocalNamespace(cg.Namespace, icg);
  509. icg.Namespace = ns;
  510. Body.Emit(icg);
  511. ns.EmitLocalsDict(icg);
  512. icg.EmitReturn();
  513. icg.Finish();
  514. cg.EmitGet(new Name("__name__"));
  515. cg.EmitCall(typeof(Ops), "ToString", new Type[] { typeof(object) }); // FIXME: doesn't handle non-existant __name__
  516. cg.EmitString(Name.String);
  517. cg.EmitObjectArray(Bases);
  518. cg.EmitNew(typeof(Tuple), new Type[] { typeof(object[]) });
  519. cg.EmitCall((MethodInfo)icg.MethodBase);
  520. cg.EmitCall(typeof(Ops), "MakeClass");
  521. if(docstring!=null)
  522. { cg.ILG.Emit(OpCodes.Dup);
  523. cg.EmitString("__doc__");
  524. cg.EmitString(docstring);
  525. cg.EmitCall(typeof(IHasAttributes), "__setattr__");
  526. }
  527. cg.EmitSet(Name);
  528. }
  529. finally { Options.Interactive = interactive; }
  530. }
  531. public override void Execute(Frame frame)
  532. { Frame dict = new Frame(frame);
  533. Body.Execute(dict);
  534. object[] bases = new object[Bases.Length];
  535. for(int i=0; i<bases.Length; i++) bases[i] = Bases[i].Evaluate(frame);
  536. frame.Set(Name.String,
  537. Ops.MakeClass(Ops.ToString(frame.Get("__name__")), Name.String, new Tuple(bases), dict.Locals));
  538. }
  539. public override void ToCode(System.Text.StringBuilder sb, int indent)
  540. { sb.Append("class ");
  541. sb.Append(Name.String);
  542. sb.Append(" (");
  543. for(int i=0; i<Bases.Length; i++)
  544. { if(i!=0) sb.Append(", ");
  545. Bases[i].ToCode(sb, 0);
  546. }
  547. sb.Append("):");
  548. StatementToCode(sb, Body, indent+Options.IndentSize);
  549. }
  550. public override void Walk(IWalker w)
  551. { if(w.Walk(this))
  552. { foreach(Expression e in Bases) e.Walk(w);
  553. Body.Walk(w);
  554. }
  555. w.PostWalk(this);
  556. }
  557. public Name Name;
  558. public Expression[] Bases;
  559. public Statement Body;
  560. string docstring;
  561. }
  562. #endregion
  563. #region ContinueStatement
  564. public class ContinueStatement : JumpStatement
  565. { public ContinueStatement() { }
  566. public ContinueStatement(string name) : base(name) { }
  567. public override void Execute(Frame frame)
  568. { throw Name==null ? ContinueException.Value : new ContinueException(Name);
  569. }
  570. public override void ToCode(System.Text.StringBuilder sb, int indent)
  571. { sb.Append("continue");
  572. if(Name!=null) sb.Append(' ').Append(Name);
  573. }
  574. }
  575. #endregion
  576. #region DefStatement
  577. public class DefStatement : Statement
  578. { public DefStatement(string name, Parameter[] parms, Statement body)
  579. { Function = new BoaFunction(this, name, parms, body);
  580. Function.Globals = GlobalFinder.Find(Function.Body);
  581. }
  582. public override void Emit(CodeGenerator cg)
  583. { Slot funcSlot = cg.Namespace.GetSlotForSet(Function.Name);
  584. Function.Emit(cg);
  585. funcSlot.EmitSet(cg);
  586. }
  587. public override void Execute(Frame frame) { frame.Set(Function.FuncName, Function.MakeFunction(frame)); }
  588. public override void ToCode(System.Text.StringBuilder sb, int indent)
  589. { sb.Append("def ");
  590. sb.Append(Function.Name.String);
  591. sb.Append("(");
  592. for(int i=0; i<Function.Parameters.Length; i++)
  593. { if(i!=0) sb.Append(", ");
  594. Function.Parameters[i].ToCode(sb);
  595. }
  596. sb.Append("):");
  597. StatementToCode(sb, Function.Body, indent+Options.IndentSize);
  598. }
  599. public override void Walk(IWalker w) { Function.Walk(w); }
  600. public BoaFunction Function;
  601. #region GlobalFinder
  602. sealed class GlobalFinder : IWalker
  603. { public static Name[] Find(Node node)
  604. { GlobalFinder gf = new GlobalFinder();
  605. node.Walk(gf);
  606. return gf.Globals==null || gf.Globals.Count==0 ? null : (Name[])gf.Globals.ToArray(typeof(Name));
  607. }
  608. public void PostWalk(Node node) { }
  609. public bool Walk(Node node)
  610. { while(node is ParenExpression) node = ((ParenExpression)node).Expression;
  611. if(node is DefStatement || node is LambdaExpression) return false; // TODO: what if 'def' and 'global' collide?
  612. else if(node is GlobalStatement)
  613. { if(Globals==null) Globals = new ArrayList();
  614. foreach(Name n in ((GlobalStatement)node).Names)
  615. if(assigned!=null && assigned.Contains(n.String))
  616. throw Ops.SyntaxError(node, "'{0}' assigned to before associated 'global' statement", n.String);
  617. else Globals.Add(n);
  618. return false;
  619. }
  620. else if(node is AssignStatement)
  621. { foreach(Expression e in ((AssignStatement)node).LHS) HandleAssignment(e);
  622. return false;
  623. }
  624. else if(node is ForStatement) HandleAssignment(((ForStatement)node).Names);
  625. else if(node is ListCompExpression)
  626. foreach(ListCompFor f in ((ListCompExpression)node).Fors) HandleAssignment(f.Names);
  627. else if(node is ExceptionStatement)
  628. foreach(ExceptClause ec in ((ExceptionStatement)node).Except) if(ec.Target!=null) HandleAssignment(ec.Target);
  629. return true;
  630. }
  631. void HandleAssignment(Expression e)
  632. { while(e is ParenExpression) e = ((ParenExpression)e).Expression;
  633. if(e is NameExpression)
  634. { if(assigned==null) assigned=new HybridDictionary();
  635. assigned[((NameExpression)e).Name.String] = null;
  636. }
  637. else if(e is TupleExpression) foreach(Expression te in ((TupleExpression)e).Expressions) HandleAssignment(te);
  638. }
  639. ArrayList Globals;
  640. HybridDictionary assigned;
  641. }
  642. #endregion
  643. }
  644. #endregion
  645. #region DelStatement
  646. public class DelStatement : Statement
  647. { public DelStatement(Expression[] exprs) { Expressions=exprs; }
  648. public override void Emit(CodeGenerator cg) { foreach(Expression e in Expressions) e.EmitDel(cg); }
  649. public override void Execute(Frame frame) { foreach(Expression e in Expressions) e.Delete(frame); }
  650. public override void ToCode(System.Text.StringBuilder sb, int indent)
  651. { sb.Append("del ");
  652. for(int i=0; i<Expressions.Length; i++)
  653. { if(i!=0) sb.Append(", ");
  654. Expressions[i].ToCode(sb, 0);
  655. }
  656. }
  657. public override void Walk(IWalker w)
  658. { if(w.Walk(this)) foreach(Expression e in Expressions) e.Walk(w);
  659. w.PostWalk(this);
  660. }
  661. public Expression[] Expressions;
  662. }
  663. #endregion
  664. #region ExceptionStatement
  665. public abstract class ExceptionStatement : Statement
  666. { public ExceptionStatement(Statement body, ExceptClause[] except) { Body=body; Except=except; }
  667. public override void Emit(CodeGenerator cg)
  668. { bool haveExcept = Except!=null && Except.Length!=0;
  669. Slot fromElse = NeedElse && haveExcept ? cg.AllocLocalTemp(typeof(bool)) : null;
  670. if(fromElse!=null)
  671. { cg.EmitInt(0);
  672. fromElse.EmitSet(cg);
  673. }
  674. Slot choice=null;
  675. if(Yields!=null)
  676. { choice = cg.AllocLocalTemp(typeof(int));
  677. Label label = cg.ILG.DefineLabel();
  678. cg.EmitInt(int.MaxValue);
  679. choice.EmitSet(cg);
  680. cg.ILG.Emit(OpCodes.Br, label);
  681. for(int i=0; i<Yields.Length; i++)
  682. { YieldStatement ys = Yields[i];
  683. for(int j=0; j<ys.Targets.Length; j++)
  684. if(ys.Targets[j].Statement==this) { cg.ILG.MarkLabel(ys.Targets[j].Label); break; }
  685. cg.EmitInt(i);
  686. choice.EmitSet(cg);
  687. if(i!=Yields.Length-1) cg.ILG.Emit(OpCodes.Br, label);
  688. }
  689. cg.ILG.MarkLabel(label);
  690. }
  691. EmitPreTry(cg);
  692. Label done = cg.ILG.BeginExceptionBlock(); // try {
  693. if(Yields!=null)
  694. { Label[] jumps = new Label[Yields.Length];
  695. for(int i=0; i<Yields.Length; i++)
  696. { YieldStatement ys = (YieldStatement)Yields[i];
  697. for(int j=0; j<ys.Targets.Length; j++)
  698. if(ys.Targets[j].Statement==this) { jumps[i] = ys.Targets[j+1].Label; break; }
  699. }
  700. choice.EmitGet(cg);
  701. cg.ILG.Emit(OpCodes.Switch, jumps);
  702. cg.FreeLocalTemp(choice);
  703. }
  704. Body.Emit(cg); // body
  705. if(NeedElse) // else
  706. { if(fromElse!=null)
  707. { cg.EmitInt(1);
  708. fromElse.EmitSet(cg);
  709. }
  710. EmitElse(cg);
  711. }
  712. if(haveExcept)
  713. { cg.ILG.BeginCatchBlock(typeof(Exception)); // } catch(Exception e) {
  714. Slot dt = cg.AllocLocalTemp(typeof(DynamicType)), type = cg.AllocLocalTemp(typeof(object)),
  715. et = cg.AllocLocalTemp(typeof(DynamicType)), e = cg.AllocLocalTemp(typeof(Exception));
  716. if(fromElse!=null) // if(fromElse) throw;
  717. { Label prop = cg.ILG.DefineLabel();
  718. fromElse.EmitGet(cg);
  719. cg.ILG.Emit(OpCodes.Brfalse_S, prop);
  720. cg.ILG.Emit(OpCodes.Rethrow);
  721. cg.ILG.MarkLabel(prop);
  722. }
  723. if(Except[0].Type!=null)
  724. { cg.ILG.Emit(OpCodes.Dup);
  725. e.EmitSet(cg);
  726. cg.EmitCall(typeof(Ops), "GetDynamicType"); // dt = GetDynamicType(e)
  727. dt.EmitSet(cg);
  728. foreach(ExceptClause ec in Except) // foreach(ExceptClause ec in Except) {
  729. { if(ec.Type==null) break;
  730. Label isDT=cg.ILG.DefineLabel(), next=cg.ILG.DefineLabel();
  731. ec.Type.Emit(cg); // type = ec.Type
  732. cg.ILG.Emit(OpCodes.Dup);
  733. type.EmitSet(cg);
  734. cg.ILG.Emit(OpCodes.Isinst, typeof(DynamicType)); // DynamicType et = type as DynamicType
  735. cg.ILG.Emit(OpCodes.Dup);
  736. et.EmitSet(cg);
  737. cg.ILG.Emit(OpCodes.Brtrue, isDT); // if(et==null) et = Ops.GetDynamicType(type)
  738. type.EmitGet(cg);
  739. cg.EmitCall(typeof(Ops), "GetDynamicType");
  740. et.EmitSet(cg);
  741. cg.ILG.MarkLabel(isDT);
  742. et.EmitGet(cg); // if(et.IsSubclassOf(dt)) {
  743. dt.EmitGet(cg);
  744. cg.EmitCall(typeof(DynamicType), "IsTryMatch");
  745. cg.ILG.Emit(OpCodes.Brfalse, next);
  746. if(ec.Target!=null) // ec.Target = e
  747. { e.EmitGet(cg);
  748. new AssignStatement(ec.Target).Emit(cg);
  749. }
  750. ec.Body.Emit(cg); // ec.Body()
  751. cg.ILG.Emit(OpCodes.Leave, done); // }
  752. cg.ILG.MarkLabel(next);
  753. }
  754. }
  755. if(Except[Except.Length-1].Type!=null) cg.ILG.Emit(OpCodes.Rethrow);
  756. else
  757. { ExceptClause ec = Except[Except.Length-1];
  758. if(ec.Target!=null)
  759. { e.EmitGet(cg);
  760. new AssignStatement(ec.Target).Emit(cg);
  761. }
  762. ec.Body.Emit(cg);
  763. }
  764. cg.FreeLocalTemp(dt);
  765. cg.FreeLocalTemp(type);
  766. cg.FreeLocalTemp(et);
  767. cg.FreeLocalTemp(e);
  768. }
  769. if(NeedFinally)
  770. { cg.ILG.BeginFinallyBlock();
  771. EmitFinally(cg);
  772. }
  773. cg.ILG.EndExceptionBlock();
  774. if(fromElse!=null) cg.FreeLocalTemp(fromElse);
  775. }
  776. public override void Execute(Frame frame)
  777. { ExecutePreTry(frame);
  778. bool fromElse=false, occurred=false;
  779. try
  780. { Body.Execute(frame);
  781. if(NeedElse) { fromElse=true; ExecuteElse(frame); }
  782. }
  783. catch(BreakException) { throw; }
  784. catch(ContinueException) { throw; }
  785. catch(Exception e)
  786. { if(fromElse) throw;
  787. occurred = true;
  788. Boa.Modules.sys.Exceptions.Push(e);
  789. DynamicType dt = Ops.GetDynamicType(e);
  790. foreach(ExceptClause ec in Except)
  791. { DynamicType et;
  792. if(ec.Type!=null)
  793. { object type = ec.Type.Evaluate(frame);
  794. et = type as DynamicType;
  795. if(et==null) et = Ops.GetDynamicType(type);
  796. }
  797. else et=null;
  798. if(et==null || et.IsSubclassOf(dt))
  799. { if(ec.Target!=null) ec.Target.Assign(e, frame);
  800. ec.Body.Execute(frame);
  801. goto done;
  802. }
  803. }
  804. done:;
  805. }
  806. finally
  807. { if(NeedFinally) ExecuteFinally(frame);
  808. if(occurred) Boa.Modules.sys.Exceptions.Pop();
  809. }
  810. }
  811. public Statement Body;
  812. public ExceptClause[] Except;
  813. public YieldStatement[] Yields;
  814. protected virtual void EmitPreTry(CodeGenerator cg) { }
  815. protected virtual void EmitBody(CodeGenerator cg) { Body.Emit(cg); }
  816. protected virtual void EmitElse(CodeGenerator cg) { }
  817. protected virtual void EmitExcept(CodeGenerator cg) { }
  818. protected virtual void EmitFinally(CodeGenerator cg) { }
  819. protected virtual void PostEmit(CodeGenerator cg) { }
  820. protected virtual void ExecutePreTry(Frame frame) { }
  821. protected virtual void ExecuteElse(Frame frame) { }
  822. protected virtual void ExecuteFinally(Frame frame) { }
  823. protected bool NeedElse, NeedFinally;
  824. }
  825. #endregion
  826. #region ExpressionStatement
  827. public class ExpressionStatement : Statement
  828. { public ExpressionStatement(Expression expr) { Expression=expr; SetLocation(expr); }
  829. public override void Emit(CodeGenerator cg)
  830. { // optimize away expressions that do nothing
  831. if(Options.Optimize && Expression.IsConstant && !Options.Interactive) return;
  832. Expression.Emit(cg);
  833. if(Options.Interactive)
  834. { Slot temp = cg.AllocLocalTemp(typeof(object));
  835. temp.EmitSet(cg);
  836. cg.EmitFieldGet(typeof(Boa.Modules.sys), "displayhook");
  837. temp.EmitGet(cg);
  838. cg.EmitCall(typeof(Ops), "Call1");
  839. cg.FreeLocalTemp(temp);
  840. }
  841. cg.ILG.Emit(OpCodes.Pop);
  842. }
  843. public override void Execute(Frame frame)
  844. { if(Options.Optimize && Expression.IsConstant) return;
  845. object ret = Expression.Evaluate(frame);
  846. if(Options.Interactive) Ops.Call(Boa.Modules.sys.displayhook, ret);
  847. }
  848. public override void ToCode(System.Text.StringBuilder sb, int indent) { Expression.ToCode(sb, indent); }
  849. public override void Walk(IWalker w)
  850. { if(w.Walk(this)) Expression.Walk(w);
  851. w.PostWalk(this);
  852. }
  853. public Expression Expression;
  854. }
  855. #endregion
  856. #region IfStatement
  857. public class IfStatement : Statement
  858. { public IfStatement(Expression test, Statement body, Statement elze) { Test=test; Body=body; Else=elze; }
  859. public override void Emit(CodeGenerator cg)
  860. { if(Options.Optimize && Test.IsConstant)
  861. { if(Ops.IsTrue(Test.GetValue())) Body.Emit(cg);
  862. else if(Else!=null) Else.Emit(cg);
  863. }
  864. else
  865. { Label endLab = cg.ILG.DefineLabel(), elseLab = Else==null ? new Label() : cg.ILG.DefineLabel();
  866. if(Options.Optimize && Test is UnaryExpression && ((UnaryExpression)Test).Op==UnaryOperator.LogicalNot)
  867. { cg.EmitIsTrue(((UnaryExpression)Test).Expression);
  868. cg.ILG.Emit(OpCodes.Brtrue, Else==null ? endLab : elseLab);
  869. }
  870. else
  871. { cg.EmitIsTrue(Test);
  872. cg.ILG.Emit(OpCodes.Brfalse, Else==null ? endLab : elseLab);
  873. }
  874. Body.Emit(cg);
  875. if(Else!=null)
  876. { cg.ILG.Emit(OpCodes.Br, endLab);
  877. cg.ILG.MarkLabel(elseLab);
  878. Else.Emit(cg);
  879. }
  880. cg.ILG.MarkLabel(endLab);
  881. }
  882. }
  883. public override void Execute(Frame frame)
  884. { if(Ops.IsTrue(Test.Evaluate(frame))) Body.Execute(frame);
  885. else if(Else!=null) Else.Execute(frame);
  886. }
  887. public override void ToCode(System.Text.StringBuilder sb, int indent) { ToCode(sb, indent, false); }
  888. public override void Walk(IWalker w)
  889. { if(w.Walk(this))
  890. { Test.Walk(w);
  891. Body.Walk(w);
  892. if(Else!=null) Else.Walk(w);
  893. }
  894. w.PostWalk(this);
  895. }
  896. public Expression Test;
  897. public Statement Body, Else;
  898. void ToCode(System.Text.StringBuilder sb, int indent, bool elif)
  899. { sb.Append(elif ? "elif " : "if ");
  900. Test.ToCode(sb, 0);
  901. sb.Append(':');
  902. StatementToCode(sb, Body, indent+Options.IndentSize);
  903. if(Else!=null)
  904. { sb.Append(' ', indent);
  905. if(Else is IfStatement) ((IfStatement)Else).ToCode(sb, indent, true);
  906. else
  907. { sb.Append("else:");
  908. StatementToCode(sb, Else, indent+Options.IndentSize);
  909. }
  910. }
  911. }
  912. }
  913. #endregion
  914. // FIXME: make this be scoped properly in functions, classes, etc
  915. #region ImportFromStatement
  916. public class ImportFromStatement : Statement
  917. { public ImportFromStatement(string module, params ImportName[] names) { Module=module; Names=names; }
  918. public override void Emit(CodeGenerator cg)
  919. { cg.TypeGenerator.ModuleField.EmitGet(cg);
  920. cg.EmitString(Module);
  921. if(Names[0].Name=="*") cg.EmitCall(typeof(Ops), "ImportStar");
  922. else
  923. { string[] names=new string[Names.Length], asNames=new string[Names.Length];
  924. for(int i=0; i<Names.Length; i++) { names[i]=Names[i].Name; asNames[i]=Names[i].AsName; }
  925. cg.EmitStringArray(names);
  926. cg.EmitStringArray(asNames);
  927. cg.EmitCall(typeof(Ops), "ImportFrom");
  928. }
  929. }
  930. public override void Execute(Frame frame)
  931. { if(Names[0].Name=="*") Ops.ImportStar(frame.Module, Module);
  932. else
  933. { string[] names=new string[Names.Length], asNames=new string[Names.Length];
  934. for(int i=0; i<Names.Length; i++) { names[i]=Names[i].Name; asNames[i]=Names[i].AsName; }
  935. Ops.ImportFrom(frame.Module, Module, names, asNames);
  936. }
  937. }
  938. public override void ToCode(System.Text.StringBuilder sb, int indent)
  939. { sb.Append("from ");
  940. sb.Append(Module);
  941. sb.Append(" import ");
  942. for(int i=0; i<Names.Length; i++)
  943. { if(i!=0) sb.Append(", ");
  944. Names[i].ToCode(sb);
  945. }
  946. }
  947. public ImportName[] Names;
  948. public string Module;
  949. }
  950. #endregion
  951. #region ImportStatement
  952. public class ImportStatement : Statement
  953. { public ImportStatement(params ImportName[] names) { Names=names; }
  954. public override void Emit(CodeGenerator cg)
  955. { foreach(ImportName n in Names)
  956. { cg.EmitString(n.Name);
  957. cg.EmitCall(typeof(Importer), n.AsName==null ? "ImportTop" : "Import", new Type[] { typeof(string) });
  958. cg.EmitSet(new Name(n.AsName==null ? n.SlotName : n.AsName, Scope.Local));
  959. }
  960. }
  961. public override void Execute(Frame frame)
  962. { foreach(ImportName n in Names)
  963. if(n.AsName==null) frame.Set(n.SlotName, Importer.ImportTop(n.Name));
  964. else frame.Set(n.AsName, Importer.Import(n.Name));
  965. }
  966. public override void ToCode(System.Text.StringBuilder sb, int indent)
  967. { sb.Append("import ");
  968. for(int i=0; i<Names.Length; i++)
  969. { if(i!=0) sb.Append(", ");
  970. Names[i].ToCode(sb);
  971. }
  972. }
  973. public ImportName[] Names;
  974. }
  975. #endregion
  976. #region ForStatement
  977. public class ForStatement : Statement
  978. { public ForStatement(Name[] names, Expression expr, Statement body, Statement elze)
  979. { if(names.Length==1) Names = new NameExpression(names[0]);
  980. else
  981. { Expression[] ne = new Expression[names.Length];
  982. for(int i=0; i<names.Length; i++) ne[i] = new NameExpression(names[i]);
  983. Names=new TupleExpression(ne);
  984. }
  985. Expression=expr; Body=body; Else=elze;
  986. }
  987. public override void Emit(CodeGenerator cg)
  988. { AssignStatement ass = new AssignStatement(Names);
  989. Slot list = cg.AllocLocalTemp(typeof(IEnumerator), true);
  990. Label start=cg.ILG.DefineLabel(), end=cg.ILG.DefineLabel(), elze=(Else==null ? end : cg.ILG.DefineLabel());
  991. Body.Walk(new JumpFinder(null, start, end));
  992. Expression.Emit(cg);
  993. cg.EmitCall(typeof(Ops), "GetEnumerator", new Type[] { typeof(object) });
  994. list.EmitSet(cg);
  995. cg.ILG.BeginExceptionBlock();
  996. cg.ILG.MarkLabel(start);
  997. list.EmitGet(cg);
  998. cg.EmitCall(typeof(IEnumerator), "MoveNext");
  999. cg.ILG.Emit(OpCodes.Brfalse, elze);
  1000. list.EmitGet(cg);
  1001. cg.EmitPropGet(typeof(IEnumerator), "Current");
  1002. ass.Emit(cg);
  1003. Body.Emit(cg);
  1004. cg.ILG.Emit(OpCodes.Br, start);
  1005. if(Else!=null)
  1006. { cg.ILG.MarkLabel(elze);
  1007. Else.Emit(cg);
  1008. }
  1009. cg.ILG.MarkLabel(end);
  1010. cg.ILG.BeginCatchBlock(typeof(StopIterationException));
  1011. cg.ILG.EndExceptionBlock();
  1012. cg.FreeLocalTemp(list);
  1013. }
  1014. public override void Execute(Frame frame)
  1015. { ConstantExpression ce = new ConstantExpression(null);
  1016. AssignStatement ass = new AssignStatement(Names, ce);
  1017. ass.Optimize();
  1018. IEnumerator e = Ops.GetEnumerator(Expression.Evaluate(frame));
  1019. while(e.MoveNext())
  1020. { ce.Value=e.Current;
  1021. ass.Execute(frame);
  1022. try { Body.Execute(frame); }
  1023. catch(BreakException ex) { if(ex.Name!=null) throw; goto done; }
  1024. catch(StopIterationException) { goto done; }
  1025. catch(ContinueException ex) { if(ex.Name!=null) throw; }
  1026. }
  1027. if(Else!=null) Else.Execute(frame);
  1028. done:;
  1029. }
  1030. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1031. { sb.Append("for ");
  1032. if(Names is TupleExpression)
  1033. { TupleExpression te = (TupleExpression)Names;
  1034. for(int i=0; i<te.Expressions.Length; i++)
  1035. { if(i!=0) sb.Append(',');
  1036. te.Expressions[i].ToCode(sb, 0);
  1037. }
  1038. }
  1039. else Names.ToCode(sb, 0);
  1040. sb.Append(" in ");
  1041. Expression.ToCode(sb, 0);
  1042. sb.Append(':');
  1043. StatementToCode(sb, Body, indent+Options.IndentSize);
  1044. }
  1045. public override void Walk(IWalker w)
  1046. { if(w.Walk(this))
  1047. { Names.Walk(w);
  1048. Expression.Walk(w);
  1049. Body.Walk(w);
  1050. if(Else!=null) Else.Walk(w);
  1051. }
  1052. w.PostWalk(this);
  1053. }
  1054. public Expression Names;
  1055. public Expression Expression;
  1056. public Statement Body, Else;
  1057. }
  1058. #endregion
  1059. #region GlobalStatement
  1060. public class GlobalStatement : Statement
  1061. { public GlobalStatement(string[] names)
  1062. { Names = new Name[names.Length];
  1063. for(int i=0; i<names.Length; i++) Names[i] = new Name(names[i], Scope.Global);
  1064. }
  1065. public override void Emit(CodeGenerator cg) { }
  1066. public override void Execute(Frame frame) { foreach(Name name in Names) frame.MarkGlobal(name.String); }
  1067. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1068. { sb.Append("global ");
  1069. for(int i=0; i<Names.Length; i++)
  1070. { if(i!=0) sb.Append(", ");
  1071. sb.Append(Names[i].String);
  1072. }
  1073. }
  1074. public Name[] Names;
  1075. }
  1076. #endregion
  1077. #region JumpStatement
  1078. public abstract class JumpStatement : Statement
  1079. { public JumpStatement() { }
  1080. public JumpStatement(string name) { Name=name; }
  1081. public override void Emit(CodeGenerator cg) { cg.ILG.Emit(NeedsLeave ? OpCodes.Leave : OpCodes.Br, Label); }
  1082. public Label Label;
  1083. public string Name;
  1084. public bool NeedsLeave;
  1085. }
  1086. #endregion
  1087. #region LockStatement
  1088. public class LockStatement : ExceptionStatement
  1089. { public LockStatement(Expression expr, Statement body) : base(body, null) { Expression=expr; NeedFinally=true; }
  1090. public override void Execute(Frame frame)
  1091. { if(Expression is TupleExpression)
  1092. { TupleExpression tup = (TupleExpression)Expression;
  1093. object[] arr = new object[tup.Expressions.Length];
  1094. for(int i=0; i<arr.Length; i++)
  1095. { arr[i] = tup.Expressions[i].Evaluate(frame);
  1096. if(arr[i]==null) throw Ops.ValueError(this, "cannot lock a null value");
  1097. }
  1098. for(int i=0; i<arr.Length; i++) System.Threading.Monitor.Enter(arr[i]);
  1099. try { Body.Execute(frame); }
  1100. finally { foreach(object o in arr) if(o!=null) System.Threading.Monitor.Exit(o); }
  1101. }
  1102. else
  1103. { object o = Expression.Evaluate(frame);
  1104. if(o==null) throw Ops.ValueError(this, "cannot lock a null value");
  1105. lock(o) Body.Execute(frame);
  1106. }
  1107. }
  1108. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1109. { sb.Append("lock ");
  1110. Expression.ToCode(sb, 0);
  1111. sb.Append(":\n");
  1112. StatementToCode(sb, Body, indent+Options.IndentSize);
  1113. }
  1114. public override void Walk(IWalker w)
  1115. { if(w.Walk(this))
  1116. { Expression.Walk(w);
  1117. Body.Walk(w);
  1118. }
  1119. w.PostWalk(this);
  1120. }
  1121. public Expression Expression;
  1122. protected override void EmitPreTry(CodeGenerator cg)
  1123. { Expression[] exprs = Expression is TupleExpression ? ((TupleExpression)Expression).Expressions
  1124. : new Expression[] { Expression };
  1125. Label good=cg.ILG.DefineLabel(), evil=exprs.Length==1 ? new Label() : cg.ILG.DefineLabel();
  1126. slots = new Slot[exprs.Length];
  1127. for(int i=0; i<exprs.Length; i++)
  1128. { slots[i] = cg.AllocLocalTemp(typeof(object), true);
  1129. exprs[i].Emit(cg);
  1130. cg.ILG.Emit(OpCodes.Dup);
  1131. slots[i].EmitSet(cg);
  1132. if(i==exprs.Length-1) cg.ILG.Emit(OpCodes.Brtrue_S, good);
  1133. else cg.ILG.Emit(OpCodes.Brfalse, evil);
  1134. }
  1135. if(exprs.Length!=1) cg.ILG.MarkLabel(evil);
  1136. cg.EmitString("cannot lock a null value");
  1137. cg.EmitNew(typeof(ValueErrorException), new Type[] { typeof(string) });
  1138. cg.ILG.Emit(OpCodes.Throw);
  1139. cg.ILG.MarkLabel(good);
  1140. foreach(Slot s in slots)
  1141. { s.EmitGet(cg);
  1142. cg.EmitCall(typeof(System.Threading.Monitor), "Enter");
  1143. }
  1144. }
  1145. protected override void EmitFinally(CodeGenerator cg)
  1146. { foreach(Slot s in slots)
  1147. { s.EmitGet(cg);
  1148. cg.EmitCall(typeof(System.Threading.Monitor), "Exit");
  1149. }
  1150. }
  1151. protected override void PostEmit(CodeGenerator cg) { foreach(Slot s in slots) cg.FreeLocalTemp(s); }
  1152. Slot[] slots;
  1153. }
  1154. #endregion
  1155. #region PassStatement
  1156. public class PassStatement : Statement
  1157. { public override void Emit(CodeGenerator cg) { }
  1158. public override void Execute(Frame frame) { }
  1159. public override void ToCode(System.Text.StringBuilder sb, int indent) { sb.Append("pass"); }
  1160. }
  1161. #endregion
  1162. // FIXME: python puts spaces between arguments
  1163. #region PrintStatement
  1164. public class PrintStatement : Statement
  1165. { public PrintStatement() { Expressions=null; TrailingNewline=true; }
  1166. public PrintStatement(Expression file) : this() { File=file; }
  1167. public PrintStatement(Expression file, Expression[] exprs, bool trailingNewline)
  1168. { File=file; Expressions=exprs; TrailingNewline=trailingNewline;
  1169. }
  1170. public override void Emit(CodeGenerator cg)
  1171. { Slot file = File==null ? null : cg.AllocLocalTemp(typeof(object));
  1172. if(file!=null)
  1173. { File.Emit(cg);
  1174. file.EmitSet(cg);
  1175. }
  1176. if(Expressions!=null)
  1177. foreach(Expression e in Expressions)
  1178. { if(file==null) cg.ILG.Emit(OpCodes.Ldnull);
  1179. else file.EmitGet(cg);
  1180. e.Emit(cg);
  1181. cg.EmitCall(typeof(Ops), "Print");
  1182. }
  1183. if(TrailingNewline || Expressions.Length==0)
  1184. { if(file==null) cg.ILG.Emit(OpCodes.Ldnull);
  1185. else file.EmitGet(cg);
  1186. cg.EmitCall(typeof(Ops), "PrintNewline");
  1187. }
  1188. if(file!=null) cg.FreeLocalTemp(file);
  1189. }
  1190. public override void Execute(Frame frame)
  1191. { object file = File==null ? null : File.Evaluate(frame);
  1192. if(Expressions!=null) foreach(Expression e in Expressions) Ops.Print(file, e.Evaluate(frame));
  1193. if(TrailingNewline || Expressions.Length==0) Ops.PrintNewline(file);
  1194. }
  1195. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1196. { sb.Append("print ");
  1197. for(int i=0; i<Expressions.Length; i++)
  1198. { if(i!=0) sb.Append(", ");
  1199. Expressions[i].ToCode(sb, 0);
  1200. }
  1201. if(!TrailingNewline) sb.Append(',');
  1202. }
  1203. public override void Walk(IWalker w)
  1204. { if(w.Walk(this) && Expressions!=null) foreach(Expression e in Expressions) e.Walk(w);
  1205. w.PostWalk(this);
  1206. }
  1207. public Expression[] Expressions;
  1208. public Expression File;
  1209. public bool TrailingNewline;
  1210. }
  1211. #endregion
  1212. // TODO: add source, line, and column to exceptions
  1213. #region RaiseStatement
  1214. public class RaiseStatement : Statement
  1215. { public RaiseStatement() { }
  1216. public RaiseStatement(Expression e) { Expression=e; }
  1217. public override void Emit(CodeGenerator cg)
  1218. { if(Expression==null) cg.ILG.Emit(OpCodes.Rethrow);
  1219. else
  1220. { Label bad=cg.ILG.DefineLabel();
  1221. Expression.Emit(cg);
  1222. cg.ILG.Emit(OpCodes.Isinst, typeof(Exception));
  1223. cg.ILG.Emit(OpCodes.Dup);
  1224. cg.ILG.Emit(OpCodes.Brfalse_S, bad);
  1225. cg.ILG.Emit(OpCodes.Throw);
  1226. cg.ILG.MarkLabel(bad);
  1227. cg.ILG.Emit(OpCodes.Pop);
  1228. cg.EmitString("exceptions must be derived from System.Exception");
  1229. cg.EmitNew(typeof(TypeErrorException), new Type[] { typeof(string) });
  1230. cg.ILG.Emit(OpCodes.Throw);
  1231. }
  1232. }
  1233. public override void Execute(Frame frame)
  1234. { if(Expression==null) throw (Exception)Boa.Modules.sys.Exceptions.Peek(); // this isn't quite the same...
  1235. else
  1236. { Exception e = Expression.Evaluate(frame) as Exception;
  1237. if(e==null) throw Ops.TypeError("exceptions must be derived from System.Exception");
  1238. throw e;
  1239. }
  1240. }
  1241. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1242. { if(Expression==null) sb.Append("raise");
  1243. else
  1244. { sb.Append("raise ");
  1245. Expression.ToCode(sb, 0);
  1246. }
  1247. }
  1248. public override void Walk(IWalker w)
  1249. { if(w.Walk(this) && Expression!=null) Expression.Walk(w);
  1250. w.PostWalk(this);
  1251. }
  1252. public Expression Expression;
  1253. }
  1254. #endregion
  1255. #region ReturnStatement
  1256. public class ReturnStatement : Statement
  1257. { public ReturnStatement() { }
  1258. public ReturnStatement(Expression expression) { Expression=expression; }
  1259. public override void Emit(CodeGenerator cg)
  1260. { if(!InGenerator) cg.EmitReturn(Expression);
  1261. else
  1262. { cg.ILG.Emit(OpCodes.Ldc_I4_0);
  1263. cg.EmitReturn();
  1264. }
  1265. }
  1266. public override void Execute(Frame frame)
  1267. { if(InGenerator) throw new NotImplementedException();
  1268. throw new ReturnException(Expression==null ? null : Expression.Evaluate(frame));
  1269. }
  1270. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1271. { if(Expression==null) sb.Append("return");
  1272. else
  1273. { sb.Append("return ");
  1274. Expression.ToCode(sb, 0);
  1275. }
  1276. }
  1277. public override void Walk(IWalker w)
  1278. { if(w.Walk(this) && Expression!=null) Expression.Walk(w);
  1279. w.PostWalk(this);
  1280. }
  1281. public Expression Expression;
  1282. public bool InGenerator;
  1283. }
  1284. #endregion
  1285. #region Suite
  1286. public class Suite : Statement
  1287. { public Suite(Statement[] stmts) { Statements=stmts; SetLocation(stmts[0].Source, stmts[0].Line, stmts[0].Column); }
  1288. public override void Emit(CodeGenerator cg)
  1289. { Label start, end;
  1290. if(Name!=null)
  1291. { start=cg.ILG.DefineLabel(); end=cg.ILG.DefineLabel();
  1292. Walk(new JumpFinder(Name, start, end));
  1293. cg.ILG.MarkLabel(start);
  1294. }
  1295. else end=new Label();
  1296. foreach(Statement stmt in Statements)
  1297. { cg.EmitPosition(stmt);
  1298. stmt.Emit(cg);
  1299. }
  1300. if(Name!=null) cg.ILG.MarkLabel(end);
  1301. }
  1302. public override void Execute(Frame frame)
  1303. { if(Name==null) foreach(Statement stmt in Statements) stmt.Execute(frame);
  1304. else
  1305. { restart:
  1306. try { foreach(Statement stmt in Statements) stmt.Execute(frame); }
  1307. catch(BreakException e) { if(e.Name!=Name) throw; }
  1308. catch(ContinueException e) { if(e.Name==Name) goto restart; throw; }
  1309. }
  1310. }
  1311. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1312. { sb.Append('\n');
  1313. if(Name!=null)
  1314. { sb.Append(Name).Append(":\n");
  1315. indent += Options.IndentSize;
  1316. }
  1317. foreach(Statement s in Statements)
  1318. { if(indent>0) sb.Append(' ', indent);
  1319. s.ToCode(sb, indent);
  1320. if(!(s is IfStatement)) sb.Append('\n');
  1321. }
  1322. }
  1323. public override void Walk(IWalker w)
  1324. { if(w.Walk(this)) foreach(Statement stmt in Statements) stmt.Walk(w);
  1325. w.PostWalk(this);
  1326. }
  1327. public Statement[] Statements;
  1328. public string Name;
  1329. }
  1330. #endregion
  1331. #region TryStatement
  1332. public class TryStatement : ExceptionStatement
  1333. { public TryStatement(Statement body, ExceptClause[] except, Statement elze, Statement final)
  1334. : base(body, except) { NeedElse=(elze!=null); NeedFinally=(final!=null); Else=elze; Finally=final; }
  1335. public override void ToCode(System.Text.StringBuilder sb, int indent)
  1336. { sb.Append("try:\n");
  1337. StatementToCode(sb, Body, indent+Options.IndentSize);
  1338. foreach(ExceptClause ec in Except)
  1339. { sb.Append(' ', indent);
  1340. ec.ToCode(sb, 0);
  1341. }
  1342. if(Else!=null)
  1343. { sb.Append(' ', indent);
  1344. sb.Append("else:");
  1345. StatementToCode(sb, Else, indent+Options.IndentSize);
  1346. }
  1347. if(Finally!=null)
  1348. { sb.Append(' ', indent);
  1349. sb.Append("finally:");
  1350. StatementToCode(sb, Finally, indent+O

Large files files are truncated, but you can click here to view the full file