From 5e341c289039bd1ac8eaf87bb21e7f0729f7ac87 Mon Sep 17 00:00:00 2001 From: atrexus <110138304+atrexus@users.noreply.github.com> Date: Sun, 11 Feb 2024 19:11:24 -0500 Subject: [PATCH] tables --- src/Unluau/Chunk/Luau/Function.cs | 22 ++++++++++++---- .../IL/Statements/Instructions/LoadValue.cs | 2 +- src/Unluau/IL/Values/Table.cs | 6 ++--- src/Unluau/IL/Visitors/ValueVisitor.cs | 25 ++++++++++++++++--- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/Unluau/Chunk/Luau/Function.cs b/src/Unluau/Chunk/Luau/Function.cs index 9d68b49..88590cc 100644 --- a/src/Unluau/Chunk/Luau/Function.cs +++ b/src/Unluau/Chunk/Luau/Function.cs @@ -346,7 +346,7 @@ public BasicBlock LiftBasicBlock(Stack stack, int startPc, int? endPc = null) case OpCode.GETIMPORT: case OpCode.NEWTABLE: { - int aux = Instructions[++pc].Value; + int aux = Instructions[pc + 1].Value; var value = instruction.Code switch { @@ -362,7 +362,7 @@ OpCode.LOADKX or // The size of the table varies. If the auxiliary instruction contains a value that is not // zero, then we use it. Otherwise we switch to the B operand. - OpCode.NEWTABLE => new Table(context, aux > 0 ? aux : (instruction.B > 0 ? (1 << (instruction.B - 1)) : 0)), + OpCode.NEWTABLE => new Table(context, aux > 0 ? Instructions[++pc].Value : (instruction.B > 0 ? (1 << (instruction.B - 1)) : 0)), OpCode.DUPTABLE => ConstantToBasicValue(context, Constants[instruction.D]), // We know this won't ever happen, but the C# compiler will cry if I don't add this. @@ -531,9 +531,22 @@ OpCode.LOADKX or } case OpCode.SETLIST: { - var table = (Table)stack.Get(instruction.D)!.Value; + var table = (Table)stack.Get(instruction.A)!.Value; + for (int i = 0; i < instruction.C - 1; ++i) + { + var entry = stack.Get(instruction.B + i)!; + + table.Entries.Add(new() + { + Context = entry.Value.Context, + Value = new Reference(context, entry) + }); + } + // Skip the auxiliary instruction + ++pc; + break; } } } @@ -575,11 +588,10 @@ private BasicValue ConstantToBasicValue(Context context, Constant constant) entries[i] = new() { Context = context, - Key = null, Value = ConstantToBasicValue(context, tableConstant.Value[i]) }; - return new Table(context, entries); + return new Table(context, entries); } throw new NotImplementedException(); diff --git a/src/Unluau/IL/Statements/Instructions/LoadValue.cs b/src/Unluau/IL/Statements/Instructions/LoadValue.cs index 83b3042..60be5ee 100644 --- a/src/Unluau/IL/Statements/Instructions/LoadValue.cs +++ b/src/Unluau/IL/Statements/Instructions/LoadValue.cs @@ -18,7 +18,7 @@ public class LoadValue(Context context, Slot slot, BasicValue value) : Instructi /// /// The value to load into the provided register. /// - public BasicValue Value { get; private set; } = value; + public BasicValue Value { get; set; } = value; /// /// Implements the recursive visitor. diff --git a/src/Unluau/IL/Values/Table.cs b/src/Unluau/IL/Values/Table.cs index b320383..b3e18e8 100644 --- a/src/Unluau/IL/Values/Table.cs +++ b/src/Unluau/IL/Values/Table.cs @@ -15,7 +15,7 @@ public sealed record TableEntry /// /// Key to the entry. /// - public required BasicValue? Key { get; set; } + public BasicValue? Key { get; set; } /// /// Value for the entry. @@ -26,7 +26,7 @@ public sealed record TableEntry /// Returns a string representation of the entry. /// /// String representation. - public override string ToString() => $"Entry({Key}, {Value})"; + public override string ToString() => Key is null ? $"Entry({Value})" : $"Entry({Key}, {Value})"; } /// @@ -74,7 +74,7 @@ public override void Visit(Visitor visitor) foreach (var entry in Entries) { entry.Value.Visit(visitor); - entry.Key.Visit(visitor); + entry.Key?.Visit(visitor); } } } diff --git a/src/Unluau/IL/Visitors/ValueVisitor.cs b/src/Unluau/IL/Visitors/ValueVisitor.cs index e91a23a..c59aac0 100644 --- a/src/Unluau/IL/Visitors/ValueVisitor.cs +++ b/src/Unluau/IL/Visitors/ValueVisitor.cs @@ -96,6 +96,8 @@ public override bool Visit(LoadValue node) { TryDelete(node, node.Slot); + node.Value = ResolveValue(node.Value); + return true; } @@ -138,8 +140,12 @@ private static BasicValue ResolveValue(BasicValue value) { if (value is Reference reference) return ResolveReference(reference); + if (value is Values.Index index) return ResolveIndex(index); + + if (value is Table table) + ResolveTable(table); return value; } @@ -168,7 +174,7 @@ private static BasicValue ResolveReference(Reference reference) /// /// Resolves an index operation. /// - /// The reference. + /// The reference. /// The resolved index. private static Values.Index ResolveIndex(Values.Index index) { @@ -178,6 +184,19 @@ private static Values.Index ResolveIndex(Values.Index index) return index; } + /// + /// Resolves a table reference. + /// + /// The reference. + /// The resolved table value. + private static Table ResolveTable(Table table) + { + foreach (var entry in table.Entries) + entry.Value = ResolveValue(entry.Value); + + return table; + } + /// /// Resolves a call operation. /// @@ -220,8 +239,8 @@ private void VisitBlockChildren(BasicBlock block) // We call .ToList() to copy the list so that there are no concurrency issues. In the end // we do end up adding/removing items in the statements list. - foreach (var statement in block.Statements.ToList()) - statement.Visit(this); + foreach (var statement in block.Statements.ToList()) + statement.Visit(this); _lastBlock = previousBlock; }