FunctionDefinitionExpression.cs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. namespace MoonSharp.Interpreter.Tree.Expressions
  9. {
  10. class FunctionDefinitionExpression : Expression, IClosureBuilder
  11. {
  12. SymbolRef[] m_ParamNames;
  13. Statement m_Statement;
  14. RuntimeScopeFrame m_StackFrame;
  15. List<SymbolRef> m_Closure = new List<SymbolRef>();
  16. public object UpvalueCreationTag { get; set; }
  17. public FunctionDefinitionExpression(LuaParser.AnonfunctiondefContext context, ScriptLoadingContext lcontext, bool pushSelfParam = false)
  18. : this(context.funcbody(), lcontext, pushSelfParam)
  19. {
  20. }
  21. public SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol)
  22. {
  23. for (int i = 0; i < m_Closure.Count; i++)
  24. {
  25. if (m_Closure[i].i_Name == symbol.i_Name)
  26. {
  27. return SymbolRef.Upvalue(symbol.i_Name, i);
  28. }
  29. }
  30. m_Closure.Add(symbol);
  31. return SymbolRef.Upvalue(symbol.i_Name, m_Closure.Count - 1);
  32. }
  33. public FunctionDefinitionExpression(LuaParser.FuncbodyContext context, ScriptLoadingContext lcontext, bool pushSelfParam = false)
  34. : base(context, lcontext)
  35. {
  36. var parlist = context.parlist();
  37. string[] paramnames;
  38. if (!pushSelfParam)
  39. {
  40. if (parlist != null)
  41. {
  42. paramnames = parlist.namelist().NAME()
  43. .Select(t => t.GetText())
  44. .ToArray();
  45. }
  46. else
  47. {
  48. paramnames = new string[0];
  49. }
  50. }
  51. else
  52. {
  53. if (parlist != null)
  54. {
  55. paramnames = new string[] { "self" }.Union(
  56. parlist.namelist().NAME()
  57. .Select(t => t.GetText()))
  58. .ToArray();
  59. }
  60. else
  61. {
  62. paramnames = new string[] { "self" };
  63. }
  64. }
  65. lcontext.Scope.EnterClosure(this);
  66. lcontext.Scope.PushFunction();
  67. m_ParamNames = DefineArguments(paramnames, lcontext);
  68. m_Statement = NodeFactory.CreateStatement(context.block(), lcontext);
  69. m_StackFrame = lcontext.Scope.PopFunction();
  70. lcontext.Scope.LeaveClosure();
  71. }
  72. private SymbolRef[] DefineArguments(string[] paramnames, ScriptLoadingContext lcontext)
  73. {
  74. SymbolRef[] ret = new SymbolRef[paramnames.Length];
  75. for (int i = 0; i < paramnames.Length; i++)
  76. ret[i] = lcontext.Scope.DefineLocal(paramnames[i]);
  77. return ret;
  78. }
  79. public int CompileBody(ByteCode bc, string friendlyName)
  80. {
  81. Instruction I = bc.Emit_Jump(OpCode.Jump, -1);
  82. bc.Emit_BeginFn(m_StackFrame, friendlyName ?? "<anonymous>");
  83. if (m_ParamNames.Length > 0)
  84. bc.Emit_Args(m_ParamNames);
  85. m_Statement.Compile(bc);
  86. bc.Emit_Ret(0);
  87. I.NumVal = bc.GetJumpPointForNextInstruction();
  88. return I.NumVal;
  89. }
  90. public int Compile(ByteCode bc, Action afterDecl, string friendlyName)
  91. {
  92. bc.Emit_Closure(m_Closure.ToArray(), bc.GetJumpPointForNextInstruction() + 3);
  93. afterDecl();
  94. return CompileBody(bc, friendlyName);
  95. }
  96. public override void Compile(ByteCode bc)
  97. {
  98. Compile(bc, () => bc.Emit_Nop(null), null);
  99. }
  100. }
  101. }