Skip to content
Open
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
59 changes: 59 additions & 0 deletions src/kOS.Safe/Compilation/Opcode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public enum ByteCode :byte
TESTARGBOTTOM = 0x61,
TESTCANCELLED = 0x62,
JUMPSTACK = 0x63,
ASSERTRANGE = 0x64,

// Augmented bogus placeholder versions of the normal
// opcodes: These only exist in the program temporarily
Expand Down Expand Up @@ -947,6 +948,64 @@ public override void Execute(ICpu cpu)
}
}

/// <summary>
/// <para>
/// Asserts that the top value of the stack is a value ranging between MinValue and MaxValue
/// </para>
/// <para></para>
/// <para>assertrange min max</para>
/// <para>... val -- ... val</para>
/// </summary>
public class OpcodeAssertRange : Opcode
{
protected override string Name { get { return "assertrange"; } }
public override ByteCode Code { get { return ByteCode.ASSERTRANGE; } }

[MLField(0, false)]
public double? MinValue { get; set; }
[MLField(1, false)]
public double? MaxValue { get; set; }

protected OpcodeAssertRange()
{
}

public OpcodeAssertRange(double min, double max)
{
MinValue = min;
MaxValue = max;
}

public override void PopulateFromMLFields(List<object> fields)
{
if (fields == null || fields.Count < 2)
throw new Exception(String.Format("Saved field in ML file for OpcodeAssertRange seems to be missing. Version mismatch?"));
MinValue = !(fields[0] is PseudoNull) ? Convert.ToDouble(fields[0]) : (double?)null;
MaxValue = !(fields[1] is PseudoNull) ? Convert.ToDouble(fields[1]) : (double?)null;
}

public override void Execute(ICpu cpu)
{
object value = cpu.PeekRawArgument(0, out bool ok);
if (!ok)
throw new KOSException("Failed to assert range: failed to load stack argument");

if (value is not ScalarValue scalar)
throw new KOSException("Failed to assert range: cannot assert range for non scalar");

double actual = scalar.GetDoubleValue();

if ((MinValue.HasValue && actual < MinValue.Value) ||
(MaxValue.HasValue && actual > MaxValue.Value))
{
throw new KOSException(
$"assertrange failed: value {value} not in range " +
$"[{MinValue?.ToString() ?? "-infinity"}, {MaxValue?.ToString() ?? "infinity"}]"
);
}
}
}

/// <summary>
/// Stops executing for this cycle. Has no stack effect.
/// </summary>
Expand Down