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
34 changes: 14 additions & 20 deletions Jint/Native/Set/SetPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ private JsBoolean IsDisjointFrom(JsValue thisObject, JsCallArguments arguments)
var set = AssertSetInstance(thisObject);
var other = arguments.At(0);
var otherRec = GetSetRecord(other);
var resultSetData = new JsSet(_engine, new OrderedSet<JsValue>(set._set._set));

if (set.Size <= otherRec.Size)
{
Expand All @@ -168,7 +167,7 @@ private JsBoolean IsDisjointFrom(JsValue thisObject, JsCallArguments arguments)
var args = new JsValue[1];
while (index < set.Size)
{
var e = resultSetData[index];
var e = set[index];
index++;
if (e is not null)
{
Expand Down Expand Up @@ -334,34 +333,30 @@ private JsBoolean IsSubsetOf(JsValue thisObject, JsCallArguments arguments)
}

var otherRec = GetSetRecord(other);
var resultSetData = new JsSet(_engine, new OrderedSet<JsValue>(set._set._set));
var thisSize = set.Size;

if (thisSize > otherRec.Size)
{
return JsBoolean.False;
}

if (thisSize <= otherRec.Size)
var index = 0;
var args = new JsValue[1];
while (index < thisSize)
{
var index = 0;
var args = new JsValue[1];
while (index < thisSize)
var e = set[index];
if (e is not null)
{
var e = resultSetData[index];
if (e is not null)
args[0] = e;
var inOther = TypeConverter.ToBoolean(otherRec.Has.Call(otherRec.Set, args));
if (!inOther)
{
args[0] = e;
var inOther = TypeConverter.ToBoolean(otherRec.Has.Call(otherRec.Set, args));
if (!inOther)
{
return JsBoolean.False;
}
return JsBoolean.False;
}

thisSize = set.Size;
index++;
}

thisSize = set.Size;
index++;
}

return JsBoolean.True;
Expand All @@ -375,8 +370,7 @@ private JsBoolean IsSupersetOf(JsValue thisObject, JsCallArguments arguments)
if (other is JsSet otherSet)
{
// fast path
var result = new HashSet<JsValue>(set._set._set, SameValueZeroComparer.Instance);
return result.IsSupersetOf(otherSet._set._set) ? JsBoolean.True : JsBoolean.False;
return set._set._set.IsSupersetOf(otherSet._set._set) ? JsBoolean.True : JsBoolean.False;
}

var thisSize = set.Size;
Expand Down
10 changes: 6 additions & 4 deletions Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -855,11 +855,12 @@ protected override object EvaluateInternal(EvaluationContext context)
var baseValue = baseNumber._value;
if (exponentNumber.IsPositiveInfinity())
{
if (Math.Abs(baseValue) > 1)
var absBase = Math.Abs(baseValue);
if (absBase > 1)
{
return JsNumber.DoublePositiveInfinity;
}
if (Math.Abs(baseValue) == 1)
if (absBase == 1)
{
return JsNumber.DoubleNaN;
}
Expand All @@ -869,11 +870,12 @@ protected override object EvaluateInternal(EvaluationContext context)

if (exponentNumber.IsNegativeInfinity())
{
if (Math.Abs(baseValue) > 1)
var absBase = Math.Abs(baseValue);
if (absBase > 1)
{
return JsNumber.PositiveZero;
}
if (Math.Abs(baseValue) == 1)
if (absBase == 1)
{
return JsNumber.DoubleNaN;
}
Expand Down
11 changes: 7 additions & 4 deletions Jint/Runtime/TypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public static class TypeConverter
private static readonly string[] intToString = new string[1024];
private static readonly string[] charToString = new string[256];

private static readonly BigInteger s_bigInt2Pow64 = BigInteger.Pow(2, 64);
private static readonly BigInteger s_bigInt2Pow63 = BigInteger.Pow(2, 63);

static TypeConverter()
{
for (var i = 0; i < intToString.Length; ++i)
Expand Down Expand Up @@ -742,10 +745,10 @@ internal static bool TryStringToBigInt(string str, out BigInteger result)
/// </summary>
internal static long ToBigInt64(BigInteger value)
{
var int64bit = BigIntegerModulo(value, BigInteger.Pow(2, 64));
if (int64bit >= BigInteger.Pow(2, 63))
var int64bit = BigIntegerModulo(value, s_bigInt2Pow64);
if (int64bit >= s_bigInt2Pow63)
{
return (long) (int64bit - BigInteger.Pow(2, 64));
return (long) (int64bit - s_bigInt2Pow64);
}

return (long) int64bit;
Expand All @@ -756,7 +759,7 @@ internal static long ToBigInt64(BigInteger value)
/// </summary>
internal static ulong ToBigUint64(BigInteger value)
{
return (ulong) BigIntegerModulo(value, BigInteger.Pow(2, 64));
return (ulong) BigIntegerModulo(value, s_bigInt2Pow64);
}

/// <summary>
Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ and many more.
#### ECMAScript proposals (no version yet)

- ✔ Await Dictionary (`Promise.allKeyed`, `Promise.allSettledKeyed`)
- ✔ Decorators (`@decorator` syntax for classes, methods, fields, and accessors)
- ✔ `Error.isError`
- ✔ Explicit Resource Management (`using` and `await using`)
- ✔ Immutable Arraybuffers
Expand Down Expand Up @@ -517,6 +518,39 @@ If `jsValue` is not a Promise it is returned immediately. If it is a rejected Pr

The synchronous `UnwrapIfPromise` is still available for scenarios where blocking is acceptable (e.g., CPU-bound scripts with no I/O), but `UnwrapIfPromiseAsync` should be preferred in any `async` call chain.

### Task/ValueTask to Promise Interop (Experimental)

When the `TaskInterop` experimental feature is enabled, .NET `Task` and `ValueTask` return values are automatically converted to JavaScript Promises. This allows JavaScript code to `await` or `.then()` the results of .NET async methods without any manual wrapping:

```c#
var engine = new Engine(options =>
{
options.ExperimentalFeatures = ExperimentalFeature.TaskInterop;
});

engine.SetValue("fetchData", new Func<string, Task<string>>(async url =>
{
using var client = new HttpClient();
return await client.GetStringAsync(url);
}));

// .NET Task is automatically converted to a JavaScript Promise
var result = engine.Evaluate("fetchData('https://example.com/api').then(data => data)");
result = result.UnwrapIfPromise();
```

Without `TaskInterop`, .NET Tasks passed to JavaScript are exposed as opaque CLR objects. With it enabled, they become native Promises that support `await`, `.then()`, and `.catch()`.

You can configure the timeout for promise resolution via `Options.Constraints.PromiseTimeout`:

```c#
var engine = new Engine(options =>
{
options.ExperimentalFeatures = ExperimentalFeature.TaskInterop;
options.Constraints.PromiseTimeout = TimeSpan.FromSeconds(10);
});
```

## .NET Interoperability

- Manipulate CLR objects from JavaScript, including:
Expand Down