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
126 changes: 120 additions & 6 deletions Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,16 @@ protected override object EvaluateInternal(EvaluationContext context)
var equal = left == right;
return equal ? JsBoolean.True : JsBoolean.False;
}

public override bool GetBooleanValue(EvaluationContext context)
{
if (!TryEvaluateOperands(context, out var left, out var right))
{
return false;
}

return left == right;
}
}

private sealed class StrictlyNotEqualBinaryExpression : JintBinaryExpression
Expand All @@ -298,6 +308,16 @@ protected override object EvaluateInternal(EvaluationContext context)

return left == right ? JsBoolean.False : JsBoolean.True;
}

public override bool GetBooleanValue(EvaluationContext context)
{
if (!TryEvaluateOperands(context, out var left, out var right))
{
return false;
}

return left != right;
}
}

private sealed class LessBinaryExpression : JintBinaryExpression
Expand All @@ -323,6 +343,23 @@ protected override object EvaluateInternal(EvaluationContext context)

return value._type == InternalTypes.Undefined ? JsBoolean.False : value;
}

public override bool GetBooleanValue(EvaluationContext context)
{
if (!TryEvaluateOperands(context, out var left, out var right))
{
return false;
}

if (context.OperatorOverloadingAllowed
&& TryOperatorOverloading(context, left, right, "op_LessThan", out var opResult))
{
return TypeConverter.ToBoolean(JsValue.FromObject(context.Engine, opResult));
}

var value = Compare(left, right);
return value._type != InternalTypes.Undefined && ((JsBoolean) value)._value;
}
}

private sealed class GreaterBinaryExpression : JintBinaryExpression
Expand All @@ -348,6 +385,23 @@ protected override object EvaluateInternal(EvaluationContext context)

return value._type == InternalTypes.Undefined ? JsBoolean.False : value;
}

public override bool GetBooleanValue(EvaluationContext context)
{
if (!TryEvaluateOperands(context, out var left, out var right))
{
return false;
}

if (context.OperatorOverloadingAllowed
&& TryOperatorOverloading(context, left, right, "op_GreaterThan", out var opResult))
{
return TypeConverter.ToBoolean(JsValue.FromObject(context.Engine, opResult));
}

var value = Compare(right, left, false);
return value._type != InternalTypes.Undefined && ((JsBoolean) value)._value;
}
}

private sealed class PlusBinaryExpression : JintBinaryExpression
Expand All @@ -374,6 +428,11 @@ protected override object EvaluateInternal(EvaluationContext context)
return JsNumber.Create((long) left.AsInteger() + right.AsInteger());
}

if (left._type == InternalTypes.Number && right._type == InternalTypes.Number)
{
return JsNumber.Create(((JsNumber) left)._value + ((JsNumber) right)._value);
}

var lprim = TypeConverter.ToPrimitive(left);
var rprim = TypeConverter.ToPrimitive(right);
JsValue result;
Expand Down Expand Up @@ -498,15 +557,21 @@ protected override object EvaluateInternal(EvaluationContext context)
return JsValue.FromObject(context.Engine, opResult);
}

JsValue number;
left = TypeConverter.ToNumeric(left);
right = TypeConverter.ToNumeric(right);

if (AreIntegerOperands(left, right))
{
number = JsNumber.Create((long) left.AsInteger() - right.AsInteger());
return JsNumber.Create((long) left.AsInteger() - right.AsInteger());
}
else if (AreNonBigIntOperands(left, right))

if (left._type == InternalTypes.Number && right._type == InternalTypes.Number)
{
return JsNumber.Create(((JsNumber) left)._value - ((JsNumber) right)._value);
}

left = TypeConverter.ToNumeric(left);
right = TypeConverter.ToNumeric(right);

JsValue number;
if (AreNonBigIntOperands(left, right))
{
number = JsNumber.Create(left.AsNumber() - right.AsNumber());
}
Expand Down Expand Up @@ -543,6 +608,10 @@ protected override object EvaluateInternal(EvaluationContext context)
{
result = JsNumber.Create((long) left.AsInteger() * right.AsInteger());
}
else if (left._type == InternalTypes.Number && right._type == InternalTypes.Number)
{
result = JsNumber.Create(((JsNumber) left)._value * ((JsNumber) right)._value);
}
else
{
var leftNumeric = TypeConverter.ToNumeric(left);
Expand Down Expand Up @@ -582,6 +651,11 @@ protected override object EvaluateInternal(EvaluationContext context)
return JsValue.FromObject(context.Engine, opResult);
}

if (left._type == InternalTypes.Number && right._type == InternalTypes.Number)
{
return JsNumber.Create(((JsNumber) left)._value / ((JsNumber) right)._value);
}

left = TypeConverter.ToNumeric(left);
right = TypeConverter.ToNumeric(right);
return Divide(context, left, right);
Expand Down Expand Up @@ -617,6 +691,26 @@ protected override object EvaluateInternal(EvaluationContext context)

return equality == !_invert ? JsBoolean.True : JsBoolean.False;
}

public override bool GetBooleanValue(EvaluationContext context)
{
if (!TryEvaluateOperands(context, out var left, out var right))
{
return false;
}

if (context.OperatorOverloadingAllowed
&& TryOperatorOverloading(context, left, right, _invert ? "op_Inequality" : "op_Equality", out var opResult))
{
return TypeConverter.ToBoolean(JsValue.FromObject(context.Engine, opResult));
}

var equality = left.Type == right.Type
? left.Equals(right)
: left.IsLooselyEqual(right);

return _invert ? !equality : equality;
}
}

private sealed class CompareBinaryExpression : JintBinaryExpression
Expand Down Expand Up @@ -647,6 +741,26 @@ protected override object EvaluateInternal(EvaluationContext context)
var value = Compare(left, right, _leftFirst);
return value.IsUndefined() || ((JsBoolean) value)._value ? JsBoolean.False : JsBoolean.True;
}

public override bool GetBooleanValue(EvaluationContext context)
{
if (!TryEvaluateOperands(context, out var leftValue, out var rightValue))
{
return false;
}

if (context.OperatorOverloadingAllowed
&& TryOperatorOverloading(context, leftValue, rightValue, _leftFirst ? "op_GreaterThanOrEqual" : "op_LessThanOrEqual", out var opResult))
{
return TypeConverter.ToBoolean(JsValue.FromObject(context.Engine, opResult));
}

var left = _leftFirst ? leftValue : rightValue;
var right = _leftFirst ? rightValue : leftValue;

var value = Compare(left, right, _leftFirst);
return !value.IsUndefined() && !((JsBoolean) value)._value;
}
}

private sealed class InstanceOfBinaryExpression : JintBinaryExpression
Expand Down
113 changes: 63 additions & 50 deletions Jint/Runtime/Interpreter/Expressions/JintExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ internal object EvaluateWithoutNodeTracking(EvaluationContext context)

protected abstract object EvaluateInternal(EvaluationContext context);

/// <summary>
/// Resolves this expression as a boolean value.
/// Comparison expressions override this to avoid creating a JsBoolean wrapper.
/// </summary>
public virtual bool GetBooleanValue(EvaluationContext context)
{
return TypeConverter.ToBoolean(GetValue(context));
}

/// <summary>
/// If we'd get Esprima source, we would just refer to it, but this makes error messages easier to decipher.
/// </summary>
Expand Down Expand Up @@ -147,8 +156,6 @@ protected internal static JintExpression Build(Expression expression)
protected static JsValue Remainder(EvaluationContext context, JsValue left, JsValue right)
{
var result = JsValue.Undefined;
left = TypeConverter.ToNumeric(left);
right = TypeConverter.ToNumeric(right);
if (AreIntegerOperands(left, right))
{
var leftInteger = left.AsInteger();
Expand All @@ -171,50 +178,56 @@ protected static JsValue Remainder(EvaluationContext context, JsValue left, JsVa
}
}
}
else if (JintBinaryExpression.AreNonBigIntOperands(left, right))
else
{
var n = left.AsNumber();
var d = right.AsNumber();
left = TypeConverter.ToNumeric(left);
right = TypeConverter.ToNumeric(right);

if (double.IsNaN(n) || double.IsNaN(d) || double.IsInfinity(n))
{
result = JsNumber.DoubleNaN;
}
else if (double.IsInfinity(d))
{
result = n;
}
else if (NumberInstance.IsPositiveZero(d) || NumberInstance.IsNegativeZero(d))
{
result = JsNumber.DoubleNaN;
}
else if (NumberInstance.IsPositiveZero(n) || NumberInstance.IsNegativeZero(n))
if (JintBinaryExpression.AreNonBigIntOperands(left, right))
{
result = n;
var n = left.AsNumber();
var d = right.AsNumber();

if (double.IsNaN(n) || double.IsNaN(d) || double.IsInfinity(n))
{
result = JsNumber.DoubleNaN;
}
else if (double.IsInfinity(d))
{
result = n;
}
else if (NumberInstance.IsPositiveZero(d) || NumberInstance.IsNegativeZero(d))
{
result = JsNumber.DoubleNaN;
}
else if (NumberInstance.IsPositiveZero(n) || NumberInstance.IsNegativeZero(n))
{
result = n;
}
else
{
result = JsNumber.Create(n % d);
}
}
else
{
result = JsNumber.Create(n % d);
}
}
else
{
JintBinaryExpression.AssertValidBigIntArithmeticOperands(left, right);
JintBinaryExpression.AssertValidBigIntArithmeticOperands(left, right);

var n = TypeConverter.ToBigInt(left);
var d = TypeConverter.ToBigInt(right);
var bn = TypeConverter.ToBigInt(left);
var bd = TypeConverter.ToBigInt(right);

if (d == 0)
{
Throw.RangeError(context.Engine.Realm, "Division by zero");
}
else if (n == 0)
{
result = JsBigInt.Zero;
}
else
{
result = JsBigInt.Create(n % d);
if (bd == 0)
{
Throw.RangeError(context.Engine.Realm, "Division by zero");
}
else if (bn == 0)
{
result = JsBigInt.Zero;
}
else
{
result = JsBigInt.Create(bn % bd);
}
}
}

Expand Down Expand Up @@ -332,29 +345,29 @@ protected static JsValue Compare(JsValue x, JsValue y, bool leftFirst = true) =>

private static JsValue CompareNumber(JsValue x, JsValue y, bool leftFirst)
{
if (x.IsInteger() && y.IsInteger())
{
return x.AsInteger() < y.AsInteger() ? JsBoolean.True : JsBoolean.False;
}

double nx, ny;
if (leftFirst)
{
nx = x.AsNumber();
ny = y.AsNumber();
nx = ((JsNumber) x)._value;
ny = ((JsNumber) y)._value;
}
else
{
ny = y.AsNumber();
nx = x.AsNumber();
ny = ((JsNumber) y)._value;
nx = ((JsNumber) x)._value;
}

if (x.IsInteger() && y.IsInteger())
if (double.IsNaN(nx) || double.IsNaN(ny))
{
return (int) nx < (int) ny ? JsBoolean.True : JsBoolean.False;
}

if (!double.IsInfinity(nx) && !double.IsInfinity(ny) && !double.IsNaN(nx) && !double.IsNaN(ny))
{
return nx < ny ? JsBoolean.True : JsBoolean.False;
return JsValue.Undefined;
}

return CompareComplex(x, y, leftFirst);
return nx < ny ? JsBoolean.True : JsBoolean.False;
}

private static JsValue CompareComplex(JsValue x, JsValue y, bool leftFirst)
Expand Down
14 changes: 6 additions & 8 deletions Jint/Runtime/Interpreter/Statements/JintForStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,16 +261,14 @@ private Completion ForBodyEvaluation(EvaluationContext context)
{
debugHandler?.OnStep(_test._expression);

var testValue = _test.GetValue(context);

// Check for async suspension in test expression
if (context.IsSuspended())
if (!_test.GetBooleanValue(context))
{
return new Completion(CompletionType.Return, JsValue.Undefined, ((JintStatement) this)._statement);
}
// Check for async suspension in test expression
if (context.IsSuspended())
{
return new Completion(CompletionType.Return, JsValue.Undefined, ((JintStatement) this)._statement);
}

if (!TypeConverter.ToBoolean(testValue))
{
return new Completion(CompletionType.Normal, v, ((JintStatement) this)._statement);
}
}
Expand Down
2 changes: 1 addition & 1 deletion Jint/Runtime/Interpreter/Statements/JintIfStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected override void Initialize(EvaluationContext context)
protected override Completion ExecuteInternal(EvaluationContext context)
{
Completion result;
if (TypeConverter.ToBoolean(_test.GetValue(context)))
if (_test.GetBooleanValue(context))
{
// B.3.2/B.3.3: IfStatement function declarations need runtime AnnexB handling
if (_consequentIsFunctionDecl && !StrictModeScope.IsStrictModeCode)
Expand Down
Loading