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;
}