Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions src/Lua.SourceGenerator/LuaObjectGenerator.Emit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ TempCollections tempCollections
return false;
}

if (!TryEmitTryIndex(typeMetadata, builder, references, compilation))
{
return false;
}

// implicit operator
builder.AppendLine(
$"public static implicit operator global::Lua.LuaValue({typeMetadata.FullTypeName} value)"
Expand Down Expand Up @@ -1212,4 +1217,122 @@ in SourceProductionContext context

return true;
}

static bool TryEmitTryIndex(
TypeMetadata typeMetadata,
CodeBuilder builder,
SymbolReferences references,
Compilation compilation
)
{
builder.AppendLine("bool global::Lua.ILuaUserData.TryIndex(global::Lua.LuaValue key, ref global::Lua.LuaValue value, bool isGet)");
using (builder.BeginBlockScope())
{
builder.AppendLine("if (!key.TryRead<string>(out var stringKey)) return false;");
builder.AppendLine($"var userData = ({typeMetadata.FullTypeName})this;");
builder.AppendLine();

builder.AppendLine("if (isGet)");
using (builder.BeginBlockScope())
{
foreach (var propertyMetadata in typeMetadata.Properties)
{
if (propertyMetadata.IsWriteOnly)
{
continue;
}

if (SymbolEqualityComparer.Default.Equals(propertyMetadata.Type, references.LuaValue))
{
if (propertyMetadata.IsStatic)
{
builder.AppendLine(
@$"if (stringKey == ""{propertyMetadata.LuaMemberName}"") {{ value = {typeMetadata.FullTypeName}.{propertyMetadata.Symbol.Name}; return true; }}"
);
}
else
{
builder.AppendLine(
@$"if (stringKey == ""{propertyMetadata.LuaMemberName}"") {{ value = userData.{propertyMetadata.Symbol.Name}; return true; }}"
);
}
}
else
{
var luaValuePrefix = GetLuaValuePrefix(propertyMetadata.Type, references, compilation);
if (propertyMetadata.IsStatic)
{
builder.AppendLine(
@$"if (stringKey == ""{propertyMetadata.LuaMemberName}"") {{ value = {luaValuePrefix}{typeMetadata.FullTypeName}.{propertyMetadata.Symbol.Name}); return true; }}"
);
}
else
{
builder.AppendLine(
@$"if (stringKey == ""{propertyMetadata.LuaMemberName}"") {{ value = {luaValuePrefix}userData.{propertyMetadata.Symbol.Name}); return true; }}"
);
}
}
}

foreach (
var methodMetadata in typeMetadata.Methods.Where(x => x.HasMemberAttribute)
)
{
builder.AppendLine(
@$"if (stringKey == ""{methodMetadata.LuaMemberName}"") {{ value = new global::Lua.LuaValue(__function_{methodMetadata.LuaMemberName}); return true; }}"
);
}
}

builder.AppendLine("else");
using (builder.BeginBlockScope())
{
foreach (var propertyMetadata in typeMetadata.Properties)
{
if (propertyMetadata.IsReadOnly)
{
continue;
}

var readExpr = GetLuaValueReadExpression(
propertyMetadata.Type,
references,
compilation
);
if (propertyMetadata.IsStatic)
{
builder.AppendLine(
@$"if (stringKey == ""{propertyMetadata.LuaMemberName}"") {{ {typeMetadata.FullTypeName}.{propertyMetadata.Symbol.Name} = {readExpr}; return true; }}"
);
}
else
{
builder.AppendLine(
@$"if (stringKey == ""{propertyMetadata.LuaMemberName}"") {{ userData.{propertyMetadata.Symbol.Name} = {readExpr}; return true; }}"
);
}
}
}

builder.AppendLine("return false;");
}
builder.AppendLine();

return true;
}

static string GetLuaValueReadExpression(ITypeSymbol type, SymbolReferences references, Compilation compilation)
{
if (SymbolEqualityComparer.Default.Equals(type, references.LuaValue))
return "value";
var typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (SymbolEqualityComparer.Default.Equals(type, references.String))
return $"value.Read<{typeName}>()";
if (SymbolEqualityComparer.Default.Equals(type, references.Double))
return $"value.Read<{typeName}>()";
if (SymbolEqualityComparer.Default.Equals(type, references.Boolean))
return $"value.Read<{typeName}>()";
return $"value.TryRead<{typeName}>(out var __readResult) ? __readResult : throw new global::System.InvalidOperationException($\"Cannot convert LuaValue type '{{value.Type}}' to '{typeName}'\")";
}
}
1 change: 1 addition & 0 deletions src/Lua/LuaUserData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ public interface ILuaUserData

// We use span for compatibility with lua5.4.
Span<LuaValue> UserValues => default;
bool TryIndex(LuaValue key, ref LuaValue value, bool isGet) => false;
}
43 changes: 43 additions & 0 deletions src/Lua/Runtime/LuaVirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,18 @@ out bool doRestart
const int MAX_LOOP = 100;
doRestart = false;
var skip = targetTable.Type == LuaValueType.Table;

if (targetTable.Type == LuaValueType.UserData)
{
var userData = targetTable.UnsafeRead<ILuaUserData>();
var result = default(LuaValue);
if (userData.TryIndex(key, ref result, true))
{
value = result;
return true;
}
}

for (var i = 0; i < MAX_LOOP; i++)
{
if (table.TryReadTable(out var luaTable))
Expand Down Expand Up @@ -2027,6 +2039,17 @@ CancellationToken ct
var targetTable = table;
const int MAX_LOOP = 100;
var skip = targetTable.Type == LuaValueType.Table;

if (targetTable.Type == LuaValueType.UserData)
{
var userData = targetTable.UnsafeRead<ILuaUserData>();
var result = default(LuaValue);
if (userData.TryIndex(key, ref result, true))
{
return new(result);
}
}

for (var i = 0; i < MAX_LOOP; i++)
{
if (table.TryReadTable(out var luaTable))
Expand Down Expand Up @@ -2124,6 +2147,16 @@ out bool doRestart
const int MAX_LOOP = 100;
doRestart = false;
var skip = targetTable.Type == LuaValueType.Table;

if (targetTable.Type == LuaValueType.UserData)
{
var userData = targetTable.UnsafeRead<ILuaUserData>();
if (userData.TryIndex(key, ref value, false))
{
return true;
}
}

for (var i = 0; i < MAX_LOOP; i++)
{
if (table.TryReadTable(out var luaTable))
Expand Down Expand Up @@ -2279,6 +2312,16 @@ CancellationToken ct
var targetTable = table;
const int MAX_LOOP = 100;
var skip = targetTable.Type == LuaValueType.Table;

if (targetTable.Type == LuaValueType.UserData)
{
var userData = targetTable.UnsafeRead<ILuaUserData>();
if (userData.TryIndex(key, ref value, false))
{
return default;
}
}

for (var i = 0; i < MAX_LOOP; i++)
{
if (table.TryReadTable(out var luaTable))
Expand Down
18 changes: 18 additions & 0 deletions src/Lua/Standard/FileHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ public sealed class FileHandle : ILuaUserData
set => fileHandleMetatable = value;
}

bool ILuaUserData.TryIndex(LuaValue key, ref LuaValue value, bool isGet)
{
if (!isGet) return false;
if (!key.TryRead<string>(out var name)) return false;
value = name switch
{
"close" => new LuaValue(CloseFunction),
"flush" => new LuaValue(FlushFunction),
"lines" => new LuaValue(LinesFunction),
"read" => new LuaValue(ReadFunction),
"seek" => new LuaValue(SeekFunction),
"setvbuf" => new LuaValue(SetVBufFunction),
"write" => new LuaValue(WriteFunction),
_ => default,
};
return value.Type != LuaValueType.Nil;
}

static LuaTable? fileHandleMetatable;

static FileHandle()
Expand Down