Skip to content

Commit 289bb76

Browse files
committed
.
1 parent 0bd6563 commit 289bb76

File tree

3 files changed

+145
-55
lines changed

3 files changed

+145
-55
lines changed

src/Asynkron.JsEngine/Ast/AssignmentReference.cs

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -319,60 +319,121 @@ internal static void AssignObjectProperty(
319319
return;
320320
}
321321

322-
var prototype = target.Prototype;
323-
while (prototype is not null)
322+
IJsPropertyAccessor? prototypeAccessor = target.PrototypeAccessor ?? target.Prototype;
323+
while (prototypeAccessor is not null)
324324
{
325-
var inheritedDescriptor = prototype.GetOwnPropertyDescriptor(propertyName);
326-
if (inheritedDescriptor is not null)
325+
if (prototypeAccessor is JsObject protoObj)
327326
{
328-
if (inheritedDescriptor.IsAccessorDescriptor)
327+
var inheritedDescriptor = protoObj.GetOwnPropertyDescriptor(propertyName);
328+
if (inheritedDescriptor is not null)
329329
{
330-
if (inheritedDescriptor.Set is null)
330+
if (inheritedDescriptor.IsAccessorDescriptor)
331+
{
332+
if (inheritedDescriptor.Set is null)
333+
{
334+
if (isStrict)
335+
{
336+
throw StandardLibrary.ThrowTypeError(
337+
$"Cannot set property '{propertyName}' that has only a getter.",
338+
context,
339+
realmState);
340+
}
341+
342+
return;
343+
}
344+
345+
TypedAstEvaluator.InvokeCallable(inheritedDescriptor.Set, [value], receiver, context);
346+
return;
347+
}
348+
349+
if (!inheritedDescriptor.Writable)
331350
{
332351
if (isStrict)
333352
{
334353
throw StandardLibrary.ThrowTypeError(
335-
$"Cannot set property '{propertyName}' that has only a getter.",
354+
$"Cannot assign to read only property '{propertyName}'.",
336355
context,
337356
realmState);
338357
}
339358

340359
return;
341360
}
342361

343-
TypedAstEvaluator.InvokeCallable(inheritedDescriptor.Set, [value], receiver, context);
362+
target.DefineProperty(propertyName, new PropertyDescriptor
363+
{
364+
Value = value,
365+
Writable = true,
366+
Enumerable = inheritedDescriptor.Enumerable,
367+
Configurable = inheritedDescriptor.Configurable,
368+
HasValue = true,
369+
HasWritable = true,
370+
HasEnumerable = inheritedDescriptor.HasEnumerable,
371+
HasConfigurable = inheritedDescriptor.HasConfigurable
372+
});
344373
return;
345374
}
346375

347-
if (!inheritedDescriptor.Writable)
376+
prototypeAccessor = protoObj.PrototypeAccessor ?? protoObj.Prototype;
377+
continue;
378+
}
379+
380+
if (prototypeAccessor is IJsObjectLike objectLike)
381+
{
382+
var inheritedDescriptor = objectLike.GetOwnPropertyDescriptor(propertyName);
383+
if (inheritedDescriptor is not null)
348384
{
349-
if (isStrict)
385+
if (inheritedDescriptor.IsAccessorDescriptor)
350386
{
351-
throw StandardLibrary.ThrowTypeError(
352-
$"Cannot assign to read only property '{propertyName}'.",
353-
context,
354-
realmState);
387+
if (inheritedDescriptor.Set is null)
388+
{
389+
if (isStrict)
390+
{
391+
throw StandardLibrary.ThrowTypeError(
392+
$"Cannot set property '{propertyName}' that has only a getter.",
393+
context,
394+
realmState);
395+
}
396+
397+
return;
398+
}
399+
400+
TypedAstEvaluator.InvokeCallable(inheritedDescriptor.Set, [value], receiver, context);
401+
return;
402+
}
403+
404+
if (!inheritedDescriptor.Writable)
405+
{
406+
if (isStrict)
407+
{
408+
throw StandardLibrary.ThrowTypeError(
409+
$"Cannot assign to read only property '{propertyName}'.",
410+
context,
411+
realmState);
412+
}
413+
414+
return;
355415
}
356416

417+
target.DefineProperty(propertyName, new PropertyDescriptor
418+
{
419+
Value = value,
420+
Writable = true,
421+
Enumerable = inheritedDescriptor.Enumerable,
422+
Configurable = inheritedDescriptor.Configurable,
423+
HasValue = true,
424+
HasWritable = true,
425+
HasEnumerable = inheritedDescriptor.HasEnumerable,
426+
HasConfigurable = inheritedDescriptor.HasConfigurable
427+
});
357428
return;
358429
}
359430

360-
// Writable inherited data property: create/update own data property
361-
target.DefineProperty(propertyName, new PropertyDescriptor
362-
{
363-
Value = value,
364-
Writable = true,
365-
Enumerable = inheritedDescriptor.Enumerable,
366-
Configurable = inheritedDescriptor.Configurable,
367-
HasValue = true,
368-
HasWritable = true,
369-
HasEnumerable = inheritedDescriptor.HasEnumerable,
370-
HasConfigurable = inheritedDescriptor.HasConfigurable
371-
});
431+
prototypeAccessor.SetProperty(propertyName, value, receiver);
372432
return;
373433
}
374434

375-
prototype = prototype.Prototype;
435+
prototypeAccessor.SetProperty(propertyName, value, receiver);
436+
return;
376437
}
377438

378439
if (!target.IsExtensible)

src/Asynkron.JsEngine/Ast/ExpressionNodeExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ private bool ContainsDirectEvalCall()
389389
return (withValue, withBinding.BindingObject, false);
390390
}
391391

392-
var calleeValue = EvaluateIdentifier(identifier, environment, context);
392+
var reference = environment.ResolveIdentifierAssignmentReference(identifier.Name, context);
393+
var calleeValue = AssignmentReferenceResolver.ReadIdentifierValue(reference.GetValue, context);
393394
if (context.ShouldStopEvaluation)
394395
{
395396
return (Symbol.Undefined, null, true);

src/Asynkron.JsEngine/JsEnvironment.cs

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,15 +1501,6 @@ private static bool TryResolveObjectBinding(
15011501
return false;
15021502
}
15031503

1504-
if (touchedUnscopables && jsObject is not null && originalDescriptor is not null)
1505-
{
1506-
var currentDescriptor = jsObject.GetOwnPropertyDescriptor(propertyName);
1507-
if (currentDescriptor is null)
1508-
{
1509-
allowMissingAssignment = true;
1510-
}
1511-
}
1512-
15131504
return true;
15141505
}
15151506

@@ -1530,15 +1521,47 @@ private static bool HasProperty(IJsObjectLike target, string name)
15301521
return true;
15311522
}
15321523

1533-
var prototype = target.Prototype;
1534-
while (prototype is not null)
1524+
var visited = new HashSet<IJsPropertyAccessor>(ReferenceEqualityComparer<IJsPropertyAccessor>.Instance);
1525+
IJsPropertyAccessor? prototypeAccessor =
1526+
(target as IPrototypeAccessorProvider)?.PrototypeAccessor ?? target.Prototype;
1527+
1528+
while (prototypeAccessor is not null && visited.Add(prototypeAccessor))
15351529
{
1536-
if (prototype.HasProperty(name))
1530+
if (prototypeAccessor is JsObject protoObj)
1531+
{
1532+
if (protoObj.HasProperty(name))
1533+
{
1534+
return true;
1535+
}
1536+
1537+
prototypeAccessor = protoObj.PrototypeAccessor ?? protoObj.Prototype;
1538+
continue;
1539+
}
1540+
1541+
if (prototypeAccessor is IJsObjectLike objectLike)
1542+
{
1543+
if (objectLike.GetOwnPropertyDescriptor(name) is not null)
1544+
{
1545+
return true;
1546+
}
1547+
1548+
prototypeAccessor =
1549+
(objectLike as IPrototypeAccessorProvider)?.PrototypeAccessor ?? objectLike.Prototype;
1550+
continue;
1551+
}
1552+
1553+
if (prototypeAccessor.TryGetProperty(name, out _))
15371554
{
15381555
return true;
15391556
}
15401557

1541-
prototype = prototype.Prototype;
1558+
if (prototypeAccessor is IPrototypeAccessorProvider provider)
1559+
{
1560+
prototypeAccessor = provider.PrototypeAccessor;
1561+
continue;
1562+
}
1563+
1564+
break;
15421565
}
15431566

15441567
return false;
@@ -1578,27 +1601,32 @@ internal static bool TrySetWithBindingValue(in ObjectEnvironmentBinding binding,
15781601
}
15791602
}
15801603

1581-
JsOps.AssignPropertyValueByName(bindingObject, propertyName, value);
1582-
1583-
var ownDescriptor = bindingObject.GetOwnPropertyDescriptor(propertyName);
1584-
if (ownDescriptor is null)
1604+
if (bindingObject is JsObject jsObject)
15851605
{
1606+
AssignmentReferenceResolver.AssignObjectProperty(
1607+
jsObject,
1608+
propertyName,
1609+
value,
1610+
binding.IsStrictReference,
1611+
null,
1612+
realm ?? jsObject.RealmState,
1613+
bindingObject);
15861614
return true;
15871615
}
15881616

1589-
if (bindingObject is not IPropertyDefinitionHost definitionHost)
1590-
{
1591-
return true;
1592-
}
1593-
1594-
if (!ownDescriptor.IsDataDescriptor)
1617+
JsOps.AssignPropertyValueByName(bindingObject, propertyName, value);
1618+
if (bindingObject is IJsObjectLike withObject &&
1619+
bindingObject is IPropertyDefinitionHost definitionHost)
15951620
{
1596-
return true;
1621+
var ownDescriptor = withObject.GetOwnPropertyDescriptor(propertyName);
1622+
if (ownDescriptor is not null && ownDescriptor.IsDataDescriptor)
1623+
{
1624+
var descriptorClone = ownDescriptor.Clone();
1625+
descriptorClone.Value = value;
1626+
definitionHost.TryDefineProperty(propertyName, descriptorClone);
1627+
}
15971628
}
15981629

1599-
var descriptorClone = ownDescriptor.Clone();
1600-
descriptorClone.Value = value;
1601-
definitionHost.TryDefineProperty(propertyName, descriptorClone);
16021630
return true;
16031631
}
16041632

0 commit comments

Comments
 (0)