Skip to content

Commit

Permalink
yay it worky
Browse files Browse the repository at this point in the history
  • Loading branch information
atrexus committed Feb 3, 2024
1 parent 83f47b6 commit e76f71b
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 10 deletions.
11 changes: 7 additions & 4 deletions src/Unluau.CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ static void Main(string[] args)
var chunk = LuauChunk.Create(stream);
var program = chunk.Lift();

using (var output = Console.OpenStandardOutput())
{
program.Visit(new OutputVisitor(output));
}
using var output = Console.OpenStandardOutput();
program.Visit(new OutputVisitor(output));

output!.WriteByte((byte)'\n');

program.Visit(new ValueVisitor());
program.Visit(new OutputVisitor(output));
//Console.WriteLine(.);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/Unluau/Chunk/Luau/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public BasicBlock LiftBasicBlock(ref int pc)
{
var startPc = pc;
var instructions = new List<IL.Instructions.Instruction>();
var slots = new SlotFrame();
var slots = new Stack();

// We could set up an infinate loop, but I hate them. By setting up a loop like this, we can
// easily break once we have processed all instructions.
Expand Down Expand Up @@ -341,6 +341,9 @@ OpCode.LOADKX or
arguments.Add(new Reference(context, slots.Get(instruction.A + i)));
}

// Pop the stack frame (slots are freed and are now 'dead')
slots.FreeFrame(instruction.A);

int? results = instruction.B == 1 ? null : instruction.B - 1;

instructions.Add(new Call(context, function, [.. arguments], results));
Expand Down
4 changes: 2 additions & 2 deletions src/Unluau/IL/Instructions/Call.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ public class Call(Context context, BasicValue callee, BasicValue[] arguments, in
/// <summary>
/// The value to perform that call operation on.
/// </summary>
public BasicValue Callee { get; private set; } = callee;
public BasicValue Callee { get; set; } = callee;

/// <summary>
/// The arguments of the call operation.
/// </summary>
public BasicValue[] Arguments { get; private set; } = arguments;
public BasicValue[] Arguments { get; set; } = arguments;

/// <summary>
/// The number of return values of the call.
Expand Down
11 changes: 11 additions & 0 deletions src/Unluau/IL/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,19 @@ public struct Context((int, int) pcScope, (int, int)? lines = null)
/// </summary>
public (int, int)? Lines { get; set; } = lines;

public static bool operator ==(Context left, Context right) => Equals(left, right);
public static bool operator !=(Context left, Context right) => !Equals(left, right);

public override string ToString()
=> $"<{PcScope.Item1}:{PcScope.Item2}{(Lines is null ? string.Empty : $",{Lines.Value.Item1}")}>";

public override readonly bool Equals(object? obj)
{
if (obj is Context context)
return context.PcScope == PcScope && Lines == context.Lines;

return false;
}
}

/// <summary>
Expand Down
19 changes: 16 additions & 3 deletions src/Unluau/IL/SlotFrame.cs → src/Unluau/IL/Stack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Unluau.IL
/// <summary>
/// Contains information on a frame of register slots.
/// </summary>
public class SlotFrame
public class Stack
{
private readonly Dictionary<int, Slot> _slots;

Expand All @@ -20,9 +20,9 @@ public class SlotFrame
public Slot Top => _slots[_slots.Keys.ToHashSet().Max()];

/// <summary>
/// Creates a new <see cref="SlotFrame"/>.
/// Creates a new <see cref="Stack"/>.
/// </summary>
public SlotFrame()
public Stack()
{
_slots = [];
}
Expand Down Expand Up @@ -57,7 +57,10 @@ public Slot Set(byte id, BasicValue basicValue)
public Slot Get(byte id)
{
if (_slots.TryGetValue(id, out Slot? value))
{
value.References++;
return value;
}

throw new InvalidOperationException($"Slot ({id}) is empty or wasn't initialized");
}
Expand All @@ -68,6 +71,16 @@ public Slot Get(byte id)
/// <param name="id">The slot number.</param>
public void Free(byte id) => _slots.Remove(id);

/// <summary>
/// Frees the current stack frame (baseSlot..Top).
/// </summary>
/// <param name="baseSlot">The base register slot.</param>
public void FreeFrame(byte baseSlot)
{
for (byte slot = baseSlot; slot < Top.Id; slot++)
_slots.Remove(slot);
}

/// <summary>
/// Gets a slot with the specifc slot number.
/// </summary>
Expand Down
87 changes: 87 additions & 0 deletions src/Unluau/IL/Visitors/ValueVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Xml.Linq;
using Unluau.IL.Blocks;
using Unluau.IL.Instructions;
using Unluau.IL.Values;

namespace Unluau.IL.Visitors
{
/// <summary>
/// Visits the IL and resolves references if possible.
/// </summary>
public class ValueVisitor : Visitor
{
private BasicBlock? _lastBlock;

public override bool Visit(BasicBlock node)
{
_lastBlock = node;

return true;
}

public override bool Visit(Call node)
{
node.Callee = ResolveValue(node.Callee);
node.Arguments = ResolveValueList(node.Arguments);

return true;
}

/// <summary>
/// Resolves a list of values in the IL.
/// </summary>
/// <param name="values">The values.</param>
/// <returns>The resolved values.</returns>
private BasicValue[] ResolveValueList(BasicValue[] values)
{
var resolved = new BasicValue[values.Length];

for (int i = 0; i < values.Length; ++i)
resolved[i] = ResolveValue(values[i]);

return resolved;
}

/// <summary>
/// Resolves a basic value in the IL.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The resolved value.</returns>
private BasicValue ResolveValue(BasicValue value)
{
if (value is Reference reference)
return ResolveReference(reference);

return value;
}

/// <summary>
/// Resolves a reference to a register slot.
/// </summary>
/// <param name="reference">The reference.</param>
/// <returns>The resolved value.</returns>
private BasicValue ResolveReference(Reference reference)
{
// If we only have one reference to a slot, then we can just replace this reference
// with its BasicValue.
if (reference.Slot.References == 1)
{
if (_lastBlock is not null)
{
var instructions = new List<Instruction>(_lastBlock.Instructions);

var match = instructions.Find(match => match.Context == reference.Slot.Value.Context);

if (match != null)
instructions.Remove(match);

_lastBlock.Instructions = instructions.ToArray();
}

return reference.Slot.Value;
}

return reference;
}
}
}

0 comments on commit e76f71b

Please sign in to comment.