JavaScript: for each evaluates its target before reading the value

A for each loop read the property's value before evaluating its target,
so a target such as (o.p = 2, t).v, t[(o.p = 3, 'w')] or a bare
@[(o.p = 2, 'k')] stored the value from before the target ran. The
target's object and name are now evaluated first and the value is read
after them (ECMA-357 section 12.3).
This commit is contained in:
dotCooCoo
2026-11-11 20:39:02 -08:00
parent 2ca196cb9c
commit b172e3672d
5 changed files with 65 additions and 11 deletions
+4 -3
View File
@@ -173,8 +173,9 @@ pub(crate) enum Op {
XmlFilterTest,
/// `state` → the XMLList of the items kept.
XmlFilterEnd,
/// `iterator name` → `iterator value`: the value under the name a `for each` got.
ForEachValue,
/// `iterator name x₁…xₙ` → `iterator name x₁…xₙ value`: the value under the name a `for each`
/// got, read after the `n` values its target pushed.
ForEachValue(u32),
/// `value` → nothing: sets the default XML namespace of the running code.
SetDefaultNamespace,
}
@@ -312,7 +313,7 @@ fn effect(op: Op, finally_tables: &[Vec<u32>]) -> Result<Effect, String> {
Op::XmlEscape(_) | Op::XmlScopeGet | Op::XmlFilterStart | Op::XmlFilterEnd => e(1, 1),
Op::XmlLiteral { parts, .. } => e(parts, 1),
Op::XmlScopeRef => e(1, 2),
Op::ForEachValue => e(2, 2),
Op::ForEachValue(n) => e(n + 2, n + 3),
Op::SetDefaultNamespace => e(1, 0),
})
}