| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- using System.Diagnostics.CodeAnalysis;
- using Lua.Internal;
- using Lua.Loaders;
- using Lua.Runtime;
- namespace Lua;
- public sealed class LuaState
- {
- public const string DefaultChunkName = "chunk";
- // states
- readonly LuaMainThread mainThread = new();
- FastListCore<UpValue> openUpValues;
- FastStackCore<LuaThread> threadStack;
- readonly LuaTable environment;
- readonly UpValue envUpValue;
- bool isRunning;
- internal UpValue EnvUpValue => envUpValue;
- internal ref FastStackCore<LuaThread> ThreadStack => ref threadStack;
- internal ref FastListCore<UpValue> OpenUpValues => ref openUpValues;
- public LuaTable Environment => environment;
- public LuaMainThread MainThread => mainThread;
- public LuaThread CurrentThread
- {
- get
- {
- if (threadStack.TryPeek(out var thread)) return thread;
- return mainThread;
- }
- }
- public ILuaModuleLoader ModuleLoader { get; set; } = FileModuleLoader.Instance;
- // metatables
- LuaTable? nilMetatable;
- LuaTable? numberMetatable;
- LuaTable? stringMetatable;
- LuaTable? booleanMetatable;
- LuaTable? functionMetatable;
- LuaTable? threadMetatable;
- public static LuaState Create()
- {
- return new();
- }
- LuaState()
- {
- environment = new();
- envUpValue = UpValue.Closed(mainThread, environment);
- }
- public async ValueTask<int> RunAsync(Chunk chunk, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
- {
- ThrowIfRunning();
- Volatile.Write(ref isRunning, true);
- try
- {
- var closure = new Closure(this, chunk);
- return await closure.InvokeAsync(new()
- {
- State = this,
- ArgumentCount = 0,
- StackPosition = 0,
- SourcePosition = null,
- RootChunkName = chunk.Name ?? DefaultChunkName,
- ChunkName = chunk.Name ?? DefaultChunkName,
- }, buffer, cancellationToken);
- }
- finally
- {
- Volatile.Write(ref isRunning, false);
- }
- }
- public void Push(LuaValue value)
- {
- CurrentThread.Stack.Push(value);
- }
- public LuaThread CreateThread(LuaFunction function, bool isProtectedMode = true)
- {
- return new LuaCoroutine(this, function, isProtectedMode);
- }
- public Traceback GetTraceback()
- {
- // TODO: optimize
- return new()
- {
- StackFrames = threadStack.AsSpan().ToArray()
- .Append(MainThread)
- .SelectMany(x => x.GetStackFrames())
- .ToArray()
- };
- }
- internal bool TryGetMetatable(LuaValue value, [NotNullWhen(true)] out LuaTable? result)
- {
- result = value.Type switch
- {
- LuaValueType.Nil => nilMetatable,
- LuaValueType.Boolean => booleanMetatable,
- LuaValueType.String => stringMetatable,
- LuaValueType.Number => numberMetatable,
- LuaValueType.Function => functionMetatable,
- LuaValueType.Thread => threadMetatable,
- LuaValueType.UserData => value.Read<LuaUserData>().Metatable,
- LuaValueType.Table => value.Read<LuaTable>().Metatable,
- _ => null
- };
- return result != null;
- }
- internal void SetMetatable(LuaValue value, LuaTable metatable)
- {
- switch (value.Type)
- {
- case LuaValueType.Nil:
- nilMetatable = metatable;
- break;
- case LuaValueType.Boolean:
- booleanMetatable = metatable;
- break;
- case LuaValueType.String:
- stringMetatable = metatable;
- break;
- case LuaValueType.Number:
- numberMetatable = metatable;
- break;
- case LuaValueType.Function:
- functionMetatable = metatable;
- break;
- case LuaValueType.Thread:
- threadMetatable = metatable;
- break;
- case LuaValueType.UserData:
- value.Read<LuaUserData>().Metatable = metatable;
- break;
- case LuaValueType.Table:
- value.Read<LuaTable>().Metatable = metatable;
- break;
- }
- }
- internal UpValue GetOrAddUpValue(LuaThread thread, int registerIndex)
- {
- foreach (var upValue in openUpValues.AsSpan())
- {
- if (upValue.RegisterIndex == registerIndex && upValue.Thread == thread)
- {
- return upValue;
- }
- }
- var newUpValue = UpValue.Open(thread, registerIndex);
- openUpValues.Add(newUpValue);
- return newUpValue;
- }
- internal void CloseUpValues(LuaThread thread, int frameBase)
- {
- for (int i = 0; i < openUpValues.Length; i++)
- {
- var upValue = openUpValues[i];
- if (upValue.Thread != thread) continue;
- if (upValue.RegisterIndex >= frameBase)
- {
- upValue.Close();
- openUpValues.RemoveAtSwapback(i);
- i--;
- }
- }
- }
- void ThrowIfRunning()
- {
- if (Volatile.Read(ref isRunning))
- {
- throw new InvalidOperationException("the lua state is currently running");
- }
- }
- }
|