ForEachLoopStatement.cs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using MoonSharp.Interpreter.Execution;
  6. using MoonSharp.Interpreter.Execution.VM;
  7. using MoonSharp.Interpreter.Grammar;
  8. using MoonSharp.Interpreter.Tree.Expressions;
  9. namespace MoonSharp.Interpreter.Tree.Statements
  10. {
  11. class ForEachLoopStatement : Statement
  12. {
  13. RuntimeScopeBlock m_StackFrame;
  14. SymbolRef[] m_Names;
  15. IVariable[] m_NameExps;
  16. Expression m_RValues;
  17. Statement m_Block;
  18. string m_DebugText;
  19. public ForEachLoopStatement(LuaParser.Stat_foreachloopContext context, ScriptLoadingContext lcontext)
  20. : base(context, lcontext)
  21. {
  22. context.explist();
  23. var explist = context.explist();
  24. m_RValues = NodeFactory.CreateExpression(explist, lcontext);
  25. lcontext.Scope.PushBlock();
  26. m_Names = context.namelist().NAME()
  27. .Select(n => n.GetText())
  28. .Select(n => lcontext.Scope.DefineLocal(n))
  29. .ToArray();
  30. m_NameExps = m_Names
  31. .Select(s => new SymbolRefExpression(context, lcontext, s))
  32. .Cast<IVariable>()
  33. .ToArray();
  34. m_Block = NodeFactory.CreateStatement(context.block(), lcontext);
  35. m_StackFrame = lcontext.Scope.PopBlock();
  36. m_DebugText = context.GetText();
  37. }
  38. public override void Compile(ByteCode bc)
  39. {
  40. //for var_1, ···, var_n in explist do block end
  41. Loop L = new Loop()
  42. {
  43. Scope = m_StackFrame
  44. };
  45. bc.LoopTracker.Loops.Push(L);
  46. // get iterator tuple
  47. m_RValues.Compile(bc);
  48. // prepares iterator tuple - stack : iterator-tuple
  49. bc.Emit_IterPrep();
  50. // loop start - stack : iterator-tuple
  51. int start = bc.GetJumpPointForNextInstruction();
  52. bc.Emit_Enter(m_StackFrame);
  53. // expand the tuple - stack : iterator-tuple, f, var, s
  54. bc.Emit_ExpTuple(0);
  55. // calls f(s, var) - stack : iterator-tuple, iteration result
  56. bc.Emit_Call(2, m_DebugText);
  57. // perform assignment of iteration result- stack : iterator-tuple, iteration result
  58. for (int i = 0; i < m_NameExps.Length; i++)
  59. m_NameExps[i].CompileAssignment(bc, 0, i);
  60. // pops - stack : iterator-tuple
  61. bc.Emit_Pop();
  62. // repushes the main iterator var - stack : iterator-tuple, main-iterator-var
  63. bc.Emit_Load(m_Names[0]);
  64. // updates the iterator tuple - stack : iterator-tuple, main-iterator-var
  65. bc.Emit_IterUpd();
  66. // checks head, jumps if nil - stack : iterator-tuple, main-iterator-var
  67. var endjump = bc.Emit_Jump(OpCode.JNil, -1);
  68. // executes the stuff - stack : iterator-tuple
  69. m_Block.Compile(bc);
  70. // loop back again - stack : iterator-tuple
  71. bc.Emit_Leave(m_StackFrame);
  72. bc.Emit_Jump(OpCode.Jump, start);
  73. bc.LoopTracker.Loops.Pop();
  74. int exitpointLoopExit = bc.GetJumpPointForNextInstruction();
  75. bc.Emit_Leave(m_StackFrame);
  76. int exitpointBreaks = bc.GetJumpPointForNextInstruction();
  77. bc.Emit_Pop();
  78. foreach (Instruction i in L.BreakJumps)
  79. i.NumVal = exitpointBreaks;
  80. endjump.NumVal = exitpointLoopExit;
  81. }
  82. }
  83. }