Skip to content
Merged
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
22 changes: 17 additions & 5 deletions src/Lua/LuaValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,13 +361,18 @@ bool TryParseToDouble(out double result)
}

var str = Unsafe.As<string>(referenceValue!);
var span = str.AsSpan().Trim();
if (span.Length == 0)
var span = str.AsSpan();
if (!span.IsEmpty && (span[0] <= ' ' || span[^1] <= ' '))
span = span.Trim(" \f\n\r\t\v");
// .NET's parser accepts trailing NULs, Unicode whitespace and named
// infinities/NaNs. A Lua numeral must end with a hex digit or decimal point.
if (span.Length == 0 || !(StringHelper.IsDigit(span[^1]) || span[^1] == '.'))
{
result = default!;
return false;
}

var numberText = span;
var sign = 1;
var first = span[0];
if (first is '+')
Expand All @@ -381,6 +386,12 @@ bool TryParseToDouble(out double result)
span = span[1..];
}

if (span.IsEmpty || !(span[0] is >= '0' and <= '9' or '.'))
{
result = default;
return false;
}

if (span.Length > 2 && span[0] is '0' && span[1] is 'x' or 'X')
{
// TODO: optimize
Expand All @@ -399,7 +410,7 @@ bool TryParseToDouble(out double result)
else
{
return double.TryParse(
str,
numberText,
NumberStyles.Float,
CultureInfo.InvariantCulture,
out result
Expand Down Expand Up @@ -769,8 +780,9 @@ CancellationToken cancellationToken
var count = await LuaVirtualMachine.Call(state, top, top, cancellationToken);
var result = count > 0 ? stack.Get(top) : Nil;
stack.SetTop(top + 1);
// Return one value, padding missing results and discarding extras.
stack.FastGet(top) = result;
// Lua 5.2 converts a numeric __tostring result to text.
stack.FastGet(top) =
result.Type == LuaValueType.Number ? new LuaValue(result.ToString()) : result;
return 1;
}
catch
Expand Down
63 changes: 47 additions & 16 deletions src/Lua/Runtime/LuaVirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,21 @@ out doRestart
continue;
}

// Lua 5.2 only invokes __eq for tables/userdata of the
// same type. Primitive inequality needs no slow-path call.
if (
vb.Type != vc.Type
|| vb.Type is not (LuaValueType.Table or LuaValueType.UserData)
)
{
if (iA == 1)
{
context.Pc++;
}

continue;
}

if (
ExecuteCompareOperationMetaMethod(
vb,
Expand Down Expand Up @@ -950,7 +965,7 @@ out doRestart
var step = Unsafe.Add(ref indexRef, 2).UnsafeReadDouble();
var index = indexRef.UnsafeReadDouble() + step;

if (step >= 0 ? index <= limit : limit <= index)
if (step > 0 ? index <= limit : limit <= index)
{
context.Pc += instruction.SBx;
indexRef = index;
Expand Down Expand Up @@ -1128,13 +1143,9 @@ OpCode opcode
[MethodImpl(MethodImplOptions.NoInlining)]
internal static double Mod(double a, double b)
{
var mod = a % b;
if ((b > 0 && mod < 0) || (b < 0 && mod > 0))
{
mod += b;
}

return mod;
// Lua 5.2 uses this expression, including its floating-point rounding.
// A sign-adjusted remainder differs for values such as 5 and 0.1.
return a - (Math.Floor(a / b) * b);
}

static void SelfPostOperation(
Expand Down Expand Up @@ -2810,6 +2821,32 @@ CancellationToken cancellationToken
}
}

static bool TryGetCompareMetamethod(
LuaGlobalState state,
LuaValue left,
LuaValue right,
string name,
out LuaValue metamethod
)
{
if (name == Metamethods.Eq)
{
metamethod = default;
return left.Type == right.Type
&& left.Type is LuaValueType.Table or LuaValueType.UserData
&& state.TryGetMetatable(left, out var leftMetatable)
&& leftMetatable.TryGetValue(name, out metamethod)
&& state.TryGetMetatable(right, out var rightMetatable)
&& (
leftMetatable == rightMetatable
|| rightMetatable.TryGetValue(name, out var other) && metamethod == other
);
}

return left.TryGetMetamethod(state, name, out metamethod)
|| right.TryGetMetamethod(state, name, out metamethod);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static bool ExecuteCompareOperationMetaMethod(
LuaValue vb,
Expand All @@ -2823,10 +2860,7 @@ out bool doRestart
doRestart = false;
var reverseLe = false;
ReCheck:
if (
vb.TryGetMetamethod(context.GlobalState, name, out var metamethod)
|| vc.TryGetMetamethod(context.GlobalState, name, out metamethod)
)
if (TryGetCompareMetamethod(context.GlobalState, vb, vc, name, out var metamethod))
{
var stack = context.Stack;
var newBase = stack.Count;
Expand Down Expand Up @@ -2959,10 +2993,7 @@ CancellationToken cancellationToken
var (name, description) = opCode.GetNameAndDescription();
var reverseLe = false;
ReCheck:
if (
vb.TryGetMetamethod(state.GlobalState, name, out var metamethod)
|| vc.TryGetMetamethod(state.GlobalState, name, out metamethod)
)
if (TryGetCompareMetamethod(state.GlobalState, vb, vc, name, out var metamethod))
{
var stack = state.Stack;
var top = stack.Count;
Expand Down
Loading
Loading