|
1 | 1 | using System; |
2 | 2 | using Asynkron.JsEngine; |
| 3 | +using Asynkron.JsEngine.Ast; |
3 | 4 |
|
4 | 5 | internal static class Program |
5 | 6 | { |
6 | 7 | private static async Task Main() |
7 | 8 | { |
8 | 9 | await using var engine = new JsEngine(); |
9 | 10 |
|
10 | | - // Test named function expression binding immutability |
11 | | - var code = """ |
12 | | -var probeBody, setBody; |
13 | | -
|
14 | | -var func = function f() { |
15 | | - probeBody = function() { return f; }; |
16 | | - setBody = function() { f = null; }; |
| 11 | + var funcObj = await engine.Evaluate(""" |
| 12 | +let ref = function * BindingIdentifier() { |
| 13 | + return BindingIdentifier; |
17 | 14 | }; |
| 15 | +ref; |
| 16 | +"""); |
18 | 17 |
|
19 | | -func(); |
20 | | -
|
21 | | -console.log('probeBody() === func:', probeBody() === func); // should be true |
| 18 | + Console.WriteLine(funcObj?.GetType().FullName); |
| 19 | + var isStrictField = funcObj?.GetType().GetField("_isLexicallyStrict", |
| 20 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 21 | + Console.WriteLine($"lexically strict: {isStrictField?.GetValue(funcObj)}"); |
22 | 22 |
|
23 | | -setBody(); // Try to reassign f to null |
| 23 | + var closureField = funcObj?.GetType().GetField("_closure", |
| 24 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 25 | + var closure = closureField?.GetValue(funcObj); |
| 26 | + Console.WriteLine($"closure strict: {(closure as Asynkron.JsEngine.JsEnvironment)?.IsStrict}"); |
| 27 | + if (closure is Asynkron.JsEngine.JsEnvironment env) |
| 28 | + { |
| 29 | + var valuesField = typeof(Asynkron.JsEngine.JsEnvironment) |
| 30 | + .GetField("_values", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 31 | + if (valuesField?.GetValue(env) is System.Collections.IDictionary map) |
| 32 | + { |
| 33 | + foreach (System.Collections.DictionaryEntry kvp in map) |
| 34 | + { |
| 35 | + var keyName = kvp.Key?.GetType().GetProperty("Name")?.GetValue(kvp.Key) as string; |
| 36 | + if (keyName == "BindingIdentifier" && kvp.Value is not null) |
| 37 | + { |
| 38 | + var bindingType = kvp.Value.GetType(); |
| 39 | + Console.WriteLine($"binding type: {bindingType.FullName}"); |
| 40 | + var constProp = bindingType.GetProperty("IsConst"); |
| 41 | + var immutableProp = bindingType.GetProperty("IsImmutableBinding"); |
| 42 | + Console.WriteLine($"IsConst={constProp?.GetValue(kvp.Value)} IsImmutable={immutableProp?.GetValue(kvp.Value)}"); |
| 43 | + } |
| 44 | + } |
| 45 | + } |
| 46 | + } |
24 | 47 |
|
25 | | -console.log('probeBody() === func after setBody():', probeBody() === func); // should STILL be true (immutable) |
26 | | -
|
27 | | -if (probeBody() !== func) { |
28 | | - throw new Error('inner binding is NOT immutable (from body). Expected func, got: ' + probeBody()); |
29 | | -} |
| 48 | + var functionField = funcObj?.GetType().GetField("_function", |
| 49 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 50 | + var realmField = funcObj?.GetType().GetField("_realmState", |
| 51 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 52 | + var homeObjectField = funcObj?.GetType().GetField("_homeObject", |
| 53 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 54 | + var capturedField = funcObj?.GetType().GetField("_capturedPrivateNameScopes", |
| 55 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 56 | + var privateScopeField = funcObj?.GetType().GetField("_privateNameScope", |
| 57 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
30 | 58 |
|
31 | | -console.log('All tests passed!'); |
32 | | -"""; |
| 59 | + var instanceType = Type.GetType("Asynkron.JsEngine.Ast.TypedAstEvaluator+TypedGeneratorInstance, Asynkron.JsEngine"); |
| 60 | + if (instanceType is not null) |
| 61 | + { |
| 62 | + var ctor = instanceType.GetConstructors(System.Reflection.BindingFlags.Instance | |
| 63 | + System.Reflection.BindingFlags.NonPublic | |
| 64 | + System.Reflection.BindingFlags.Public)[0]; |
| 65 | + var instance = ctor.Invoke(new[] |
| 66 | + { |
| 67 | + functionField!.GetValue(funcObj), |
| 68 | + closure, |
| 69 | + Array.Empty<object?>(), |
| 70 | + null, |
| 71 | + funcObj, |
| 72 | + realmField!.GetValue(funcObj), |
| 73 | + isStrictField!.GetValue(funcObj), |
| 74 | + homeObjectField!.GetValue(funcObj), |
| 75 | + privateScopeField!.GetValue(funcObj), |
| 76 | + capturedField!.GetValue(funcObj)! |
| 77 | + }); |
| 78 | + var strictField = instanceType.GetField("_isStrict", |
| 79 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 80 | + Console.WriteLine($"reflected instance _isStrict: {strictField?.GetValue(instance)}"); |
33 | 81 |
|
34 | | - await engine.Evaluate(code); |
| 82 | + var ensureEnv = instanceType.GetMethod("EnsureExecutionEnvironment", |
| 83 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 84 | + var execEnv = ensureEnv?.Invoke(instance, Array.Empty<object?>()) as JsEnvironment; |
| 85 | + var ensureCtx = instanceType.GetMethod("EnsureEvaluationContext", |
| 86 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 87 | + var ctx = ensureCtx?.Invoke(instance, Array.Empty<object?>()) as EvaluationContext; |
| 88 | + var getFuncScope = typeof(JsEnvironment).GetMethod("GetFunctionScope", |
| 89 | + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); |
| 90 | + var funcScope = getFuncScope?.Invoke(execEnv, null) as JsEnvironment; |
| 91 | + Console.WriteLine($"execEnv strict={execEnv?.IsStrict} funcScopeStrict={funcScope?.IsStrict}"); |
| 92 | + Console.WriteLine($"context strict scope={ctx?.CurrentScope.IsStrict}"); |
| 93 | + } |
35 | 94 | } |
36 | 95 | } |
0 commit comments