ScopeCompilationContext.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System.Collections.Concurrent;
  2. using System.Runtime.CompilerServices;
  3. using Lua.Internal;
  4. using Lua.Runtime;
  5. namespace Lua.CodeAnalysis.Compilation;
  6. public class ScopeCompilationContext : IDisposable
  7. {
  8. static class Pool
  9. {
  10. static ConcurrentStack<ScopeCompilationContext> stack = new();
  11. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  12. public static ScopeCompilationContext Rent()
  13. {
  14. if (!stack.TryPop(out var context))
  15. {
  16. context = new();
  17. }
  18. return context;
  19. }
  20. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  21. public static void Return(ScopeCompilationContext context)
  22. {
  23. context.Reset();
  24. stack.Push(context);
  25. }
  26. }
  27. readonly Dictionary<ReadOnlyMemory<char>, LocalVariableDescription> localVariables = new(256, Utf16StringMemoryComparer.Default);
  28. readonly Dictionary<ReadOnlyMemory<char>, LabelDescription> labels = new(32, Utf16StringMemoryComparer.Default);
  29. public byte StackStartPosition { get; private set; }
  30. public byte StackPosition { get; set; }
  31. public byte StackTopPosition
  32. {
  33. get => (byte)(StackPosition - 1);
  34. }
  35. public bool HasCapturedLocalVariables { get; internal set; }
  36. /// <summary>
  37. /// Function context
  38. /// </summary>
  39. public FunctionCompilationContext Function { get; internal set; } = default!;
  40. /// <summary>
  41. /// Parent scope context
  42. /// </summary>
  43. public ScopeCompilationContext? Parent { get; private set; }
  44. public ScopeCompilationContext CreateChildScope()
  45. {
  46. var childScope = Pool.Rent();
  47. childScope.Parent = this;
  48. childScope.Function = Function;
  49. childScope.StackStartPosition = StackPosition;
  50. childScope.StackPosition = StackPosition;
  51. return childScope;
  52. }
  53. public FunctionCompilationContext CreateChildFunction()
  54. {
  55. var context = FunctionCompilationContext.Create(this);
  56. return context;
  57. }
  58. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  59. public void PushInstruction(in Instruction instruction, SourcePosition position, bool incrementStackPosition = false)
  60. {
  61. Function.PushInstruction(instruction, position);
  62. if (incrementStackPosition) StackPosition++;
  63. Function.MaxStackPosition = Math.Max(Function.MaxStackPosition, StackPosition);
  64. }
  65. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  66. public void TryPushCloseUpValue(byte top, SourcePosition position)
  67. {
  68. if (HasCapturedLocalVariables && top != 0)
  69. {
  70. Function.PushInstruction(Instruction.Jmp(top, 0), position);
  71. }
  72. }
  73. /// <summary>
  74. /// Add new local variable.
  75. /// </summary>
  76. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  77. public void AddLocalVariable(ReadOnlyMemory<char> name, LocalVariableDescription description)
  78. {
  79. localVariables[name] = description;
  80. }
  81. /// <summary>
  82. /// Gets the local variable in scope.
  83. /// </summary>
  84. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  85. public bool TryGetLocalVariable(ReadOnlyMemory<char> name, out LocalVariableDescription description)
  86. {
  87. if (localVariables.TryGetValue(name, out description)) return true;
  88. // Find local variables defined in the same function
  89. if (Parent != null)
  90. {
  91. return Parent.TryGetLocalVariable(name, out description);
  92. }
  93. return false;
  94. }
  95. /// <summary>
  96. /// Gets the local variable in this scope.
  97. /// </summary>
  98. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  99. public bool TryGetLocalVariableInThisScope(ReadOnlyMemory<char> name, out LocalVariableDescription description)
  100. {
  101. return localVariables.TryGetValue(name, out description);
  102. }
  103. /// <summary>
  104. /// Add new label.
  105. /// </summary>
  106. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  107. public void AddLabel(LabelDescription description)
  108. {
  109. labels.Add(description.Name, description);
  110. }
  111. /// <summary>
  112. /// Gets the label in scope.
  113. /// </summary>
  114. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  115. public bool TryGetLabel(ReadOnlyMemory<char> name, out LabelDescription description)
  116. {
  117. if (labels.TryGetValue(name, out description)) return true;
  118. // Find labels defined in the same function
  119. if (Parent != null)
  120. {
  121. return Parent.TryGetLabel(name, out description);
  122. }
  123. return false;
  124. }
  125. /// <summary>
  126. /// Resets the values ​​held in the context.
  127. /// </summary>
  128. public void Reset()
  129. {
  130. Parent = null;
  131. StackStartPosition = 0;
  132. StackPosition = 0;
  133. HasCapturedLocalVariables = false;
  134. localVariables.Clear();
  135. labels.Clear();
  136. }
  137. /// <summary>
  138. /// Returns the context object to the pool.
  139. /// </summary>
  140. public void Dispose()
  141. {
  142. Function = null!;
  143. Pool.Return(this);
  144. }
  145. }