Skip to content

Commit 95f25aa

Browse files
authored
Improve function interop (#1074)
* script functions should resolve to same reference * fix construct crashing without context
1 parent 999ce2e commit 95f25aa

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

Jint.Tests/Runtime/FunctionTests.cs

+67
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,72 @@ void addListener(Func<JsValue, JsValue[], JsValue> callback)
158158
ev(null, new JsValue[] { 20 });
159159
Assert.Equal(30, engine.Evaluate("a"));
160160
}
161+
162+
163+
[Fact]
164+
public void BoundFunctionsCanBePassedToHost()
165+
{
166+
var engine = new Engine();
167+
Func<JsValue, JsValue[], JsValue> ev = null;
168+
169+
void addListener(Func<JsValue, JsValue[], JsValue> callback)
170+
{
171+
ev = callback;
172+
}
173+
174+
engine.SetValue("addListener", new Action<Func<JsValue, JsValue[], JsValue>>(addListener));
175+
176+
engine.Execute(@"
177+
var a = 5;
178+
179+
(function() {
180+
addListener(function (acc, val) {
181+
a = (val || 0) + acc;
182+
}.bind(null, 10));
183+
})();
184+
");
185+
186+
Assert.Equal(5, engine.Evaluate("a"));
187+
188+
ev(null, new JsValue[0]);
189+
Assert.Equal(10, engine.Evaluate("a"));
190+
191+
ev(null, new JsValue[] { 20 });
192+
Assert.Equal(30, engine.Evaluate("a"));
193+
}
194+
195+
[Fact]
196+
public void ConstructorsCanBePassedToHost()
197+
{
198+
var engine = new Engine();
199+
Func<JsValue, JsValue[], JsValue> ev = null;
200+
201+
void addListener(Func<JsValue, JsValue[], JsValue> callback)
202+
{
203+
ev = callback;
204+
}
205+
206+
engine.SetValue("addListener", new Action<Func<JsValue, JsValue[], JsValue>>(addListener));
207+
208+
engine.Execute(@"addListener(Boolean)");
209+
210+
Assert.Equal(true, ev(JsValue.Undefined, new JsValue[] { "test" }));
211+
Assert.Equal(true, ev(JsValue.Undefined, new JsValue[] { 5 }));
212+
Assert.Equal(false, ev(JsValue.Undefined, new JsValue[] { false }));
213+
Assert.Equal(false, ev(JsValue.Undefined, new JsValue[] { 0}));
214+
Assert.Equal(false, ev(JsValue.Undefined, new JsValue[] { JsValue.Undefined }));
215+
}
216+
217+
218+
[Fact]
219+
public void FunctionsShouldResolveToSameReference()
220+
{
221+
var engine = new Engine();
222+
engine.SetValue("equal", new Action<object, object>(Assert.Equal));
223+
engine.Execute(@"
224+
function testFn() {}
225+
equal(testFn, testFn);
226+
");
227+
}
161228
}
162229
}

Jint/Native/Function/FunctionInstance.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ internal void OrdinaryCallBindThis(ExecutionContext calleeContext, JsValue thisA
307307
}
308308
else
309309
{
310-
if (thisArgument.IsNullOrUndefined())
310+
if (thisArgument is null || thisArgument.IsNullOrUndefined())
311311
{
312312
var globalEnv = calleeRealm.GlobalEnv;
313313
thisValue = globalEnv.GlobalThisValue;

Jint/Native/Function/ScriptFunctionInstance.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
138138
{
139139
try
140140
{
141-
var result = OrdinaryCallEvaluateBody(_engine._activeEvaluationContext, arguments, calleeContext);
141+
var context = _engine._activeEvaluationContext ?? new EvaluationContext(_engine);
142+
var result = OrdinaryCallEvaluateBody(context, arguments, calleeContext);
142143

143144
// The DebugHandler needs the current execution context before the return for stepping through the return point
144145
if (_engine._isDebugMode && result.Type != CompletionType.Throw)

Jint/Native/Object/ObjectInstance.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -959,10 +959,9 @@ private object ToObject(ObjectTraverseStack stack)
959959
break;
960960

961961
case ObjectClass.Function:
962-
if (this is FunctionInstance function)
962+
if (this is ICallable function)
963963
{
964-
converted = new Func<JsValue, JsValue[], JsValue>(
965-
(thisVal, args) => function.Engine.Invoke(function, (object) thisVal, args));
964+
converted = (Func<JsValue, JsValue[], JsValue>) function.Call;
966965
}
967966

968967
break;

0 commit comments

Comments
 (0)