Browse Source

Fix BigInt arithmetic assignments (#1891)

Marko Lahma 1 year ago
parent
commit
c06d368c9d

+ 29 - 0
Jint.Tests/Runtime/BigIntTests.cs

@@ -0,0 +1,29 @@
+using Jint.Native;
+
+namespace Jint.Tests.Runtime;
+
+public class BigIntTests
+{
+    [Theory]
+    [InlineData("a = a + b;", "146")]
+    [InlineData("a = a - b;", "100")]
+    [InlineData("a = a * b;", "2829")]
+    [InlineData("a = a / b;", "5")]
+    [InlineData("a += b;", "146")]
+    [InlineData("a -= b;", "100")]
+    [InlineData("a *= b;", "2829")]
+    [InlineData("a /= b;", "5")]
+    public void BasicOperations(string statement, string expected)
+    {
+        var outputValues = new List<JsValue>();
+        var engine = new Engine()
+            .SetValue("log", outputValues.Add);
+        engine.Evaluate("let a = 123n; let b = 23n;");
+
+        engine.Evaluate(statement);
+
+        engine.Evaluate("log(a)");
+        Assert.True(outputValues[0].IsBigInt(), "The type of the value is expected to stay BigInt");
+        Assert.Equal(expected, outputValues[0].ToString());
+    }
+}

+ 2 - 4
Jint/Native/JsBigInt.cs

@@ -19,6 +19,7 @@ public sealed class JsBigInt : JsValue, IEquatable<JsBigInt>
         {
             bigIntegers[i] = new JsBigInt(i);
         }
+
         _bigIntegerToJsValue = bigIntegers;
     }
 
@@ -40,12 +41,9 @@ public sealed class JsBigInt : JsValue, IEquatable<JsBigInt>
 
     internal static JsBigInt Create(JsValue value)
     {
-        return value is JsBigInt jsBigInt
-            ? jsBigInt
-            : Create(TypeConverter.ToBigInt(value));
+        return value as JsBigInt ?? Create(TypeConverter.ToBigInt(value));
     }
 
-
     public override object ToObject() => _value;
 
     internal override bool ToBoolean() => _value != 0;

+ 9 - 6
Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs

@@ -101,13 +101,14 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                                 newLeftValue = jsString.Append(rprim);
                             }
-                            else if (!AreIntegerOperands(originalLeftValue, rval))
+                            else if (JintBinaryExpression.AreNonBigIntOperands(originalLeftValue, rval))
                             {
                                 newLeftValue = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
                             }
                             else
                             {
-                                newLeftValue = TypeConverter.ToBigInt(lprim) + TypeConverter.ToBigInt(rprim);
+                                JintBinaryExpression.AssertValidBigIntArithmeticOperands(lprim, rprim);
+                                newLeftValue = JsBigInt.Create(TypeConverter.ToBigInt(lprim) + TypeConverter.ToBigInt(rprim));
                             }
                         }
 
@@ -121,13 +122,14 @@ namespace Jint.Runtime.Interpreter.Expressions
                         {
                             newLeftValue = JsNumber.Create(originalLeftValue.AsInteger() - rval.AsInteger());
                         }
-                        else if (!AreIntegerOperands(originalLeftValue, rval))
+                        else if (JintBinaryExpression.AreNonBigIntOperands(originalLeftValue, rval))
                         {
                             newLeftValue = JsNumber.Create(TypeConverter.ToNumber(originalLeftValue) - TypeConverter.ToNumber(rval));
                         }
                         else
                         {
-                            newLeftValue = JsNumber.Create(TypeConverter.ToBigInt(originalLeftValue) - TypeConverter.ToBigInt(rval));
+                            JintBinaryExpression.AssertValidBigIntArithmeticOperands(originalLeftValue, rval);
+                            newLeftValue = JsBigInt.Create(TypeConverter.ToBigInt(originalLeftValue) - TypeConverter.ToBigInt(rval));
                         }
 
                         break;
@@ -144,13 +146,14 @@ namespace Jint.Runtime.Interpreter.Expressions
                         {
                             newLeftValue = JsValue.Undefined;
                         }
-                        else if (!AreIntegerOperands(originalLeftValue, rval))
+                        else if (JintBinaryExpression.AreNonBigIntOperands(originalLeftValue, rval))
                         {
                             newLeftValue = TypeConverter.ToNumber(originalLeftValue) * TypeConverter.ToNumber(rval);
                         }
                         else
                         {
-                            newLeftValue = TypeConverter.ToBigInt(originalLeftValue) * TypeConverter.ToBigInt(rval);
+                            JintBinaryExpression.AssertValidBigIntArithmeticOperands(originalLeftValue, rval);
+                            newLeftValue = JsBigInt.Create(TypeConverter.ToBigInt(originalLeftValue) * TypeConverter.ToBigInt(rval));
                         }
 
                         break;

+ 1 - 0
Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs

@@ -357,6 +357,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
                 else
                 {
+                    JintBinaryExpression.AssertValidBigIntArithmeticOperands(left, right);
                     number = JsBigInt.Create(TypeConverter.ToBigInt(left) - TypeConverter.ToBigInt(right));
                 }