atmos/os_lib/js/interp/iter_gen.rs
1// 分割: interp.rs の `impl Interp` から機械的に移動(2026-07-16 リファクタ フェーズ5)。
2// ロジック不変。メソッド可視性のみ pub(crate) へ昇格(別モジュールの impl Interp
3// からの self 呼び出しのため)。impl ブロックは型 Interp に自動で結合する。
4use super::*;
5
6impl Interp {
7 /// for-in / for-of の列挙対象を Value のリストへ。
8 /// generator は遅延駆動するため `&mut self` が必要。
9 pub(crate) fn iterate_values(&mut self, obj: &Value, of: bool) -> Vec<Value> {
10 // `Proxy` は自身が Array/Set/Map/Generator の種別を持たないため、素通しすると
11 // 常に空になっていた(`for (const x of new Proxy([1,2,3], {}))` が何も回さない
12 // バグ)。target フォワードのみの Proxy を想定し、先に target まで辿っておく。
13 let obj = &{
14 let mut cur = obj.clone();
15 let mut guard = 0u32;
16 loop {
17 let next = match &cur {
18 Value::Object(o) => match &o.borrow().kind {
19 ObjKind::Proxy { target, .. } => Some(Value::Object(target.clone())),
20 _ => None,
21 },
22 _ => None,
23 };
24 match next {
25 // Proxy チェーンが循環参照(target が自分自身、または target 経由で
26 // 自分に戻ってくる)している場合、他のここでの全てのループ・再帰と
27 // 同様に上限で打ち切る。以前はガード無しで無限ループになり得た。
28 Some(v) if guard < 64 => {
29 cur = v;
30 guard += 1;
31 }
32 _ => break cur,
33 }
34 }
35 };
36 // generator は専用ドライバで全要素を取り出す(無限 gen はステップ予算で打ち切り)。
37 if of {
38 if let Value::Object(o) = obj {
39 if matches!(&o.borrow().kind, ObjKind::Generator(_)) {
40 return self.drain_generator(o);
41 }
42 }
43 }
44 // ユーザー定義の `[Symbol.iterator](){}`(class 等で定義されるカスタムイテラブル)。
45 // Array/Set/Map は専用の高速経路(下の match)を使うのでここでは対象外にする。
46 // for-await の Symbol.asyncIterator 処理と同じ「iterator.next() を回して
47 // {value,done} を読む」駆動方式(無限イテレータはステップ予算 tick() で打ち切る)。
48 if of {
49 if let Value::Object(o) = obj {
50 let is_builtin = matches!(
51 &o.borrow().kind,
52 ObjKind::Array(_) | ObjKind::SetObj(_) | ObjKind::MapObj(_)
53 );
54 if !is_builtin {
55 let iter_method = self
56 .get_property(obj, "Symbol(Symbol.iterator)")
57 .unwrap_or(Value::Undefined);
58 if matches!(&iter_method, Value::Object(f) if f.borrow().is_callable()) {
59 let iterator = self
60 .call_value(&iter_method, obj.clone(), &[])
61 .unwrap_or(Value::Undefined);
62 let mut out = Vec::new();
63 loop {
64 if self.tick() {
65 break;
66 }
67 let next_fn = match self.get_property(&iterator, "next") {
68 Ok(v) => v,
69 Err(_) => break,
70 };
71 let result =
72 match self.call_value(&next_fn, iterator.clone(), &[]) {
73 Ok(v) => v,
74 Err(_) => break,
75 };
76 let done = self
77 .get_property(&result, "done")
78 .map(|v| v.truthy())
79 .unwrap_or(true);
80 if done {
81 break;
82 }
83 let value =
84 self.get_property(&result, "value").unwrap_or(Value::Undefined);
85 out.push(value);
86 }
87 return out;
88 }
89 }
90 }
91 }
92 match obj {
93 Value::Object(o) => {
94 let b = o.borrow();
95 match &b.kind {
96 ObjKind::Array(items) => {
97 if of {
98 items.clone()
99 } else {
100 // for-in: インデックス文字列。
101 (0..items.len())
102 .map(|i| Value::str(i.to_string()))
103 .collect()
104 }
105 }
106 ObjKind::SetObj(_) | ObjKind::MapObj(_) if of => {
107 drop(b);
108 iterable_values(obj)
109 }
110 // `element.classList`(`DOMTokenList`)は仕様上イテラブルだが、専用の
111 // `Host("classList:N")` プロキシに `Symbol.iterator` が一切配線されて
112 // おらず、`for (const c of el.classList)`/`[...el.classList]` が常に
113 // 何も反復しないバグだった(`forEach()` の欠落と対)。
114 ObjKind::Host(t) if of && t.starts_with("classList:") => {
115 let cidx: usize = t.strip_prefix("classList:").and_then(|s| s.parse().ok()).unwrap_or(usize::MAX);
116 drop(b);
117 self.dom
118 .borrow()
119 .nodes
120 .get(cidx)
121 .map(|n| n.classes.iter().cloned().map(Value::str).collect())
122 .unwrap_or_default()
123 }
124 // `localStorage`/`sessionStorage` は実データを `.props` ではなく専用マップに
125 // 持つため、そちらを素通しすると `for (const k in localStorage)` が常に
126 // 何も回さないバグだった(`Object.keys(localStorage)` と同種)。仕様上
127 // Storage は for-of 対象(Symbol.iterator 実装)ではないため for-in のみ。
128 _ if !of && super::super::builtins::storage_host_keys(&b.kind).is_some() => {
129 super::super::builtins::storage_host_keys(&b.kind)
130 .unwrap_or_default()
131 .into_iter()
132 .map(Value::str)
133 .collect()
134 }
135 // `element.dataset` も同種のバグで `for (const k in el.dataset)` が
136 // 常に何も回さなかった(実データは DOM 要素側の `data-*` 属性)。
137 _ if !of
138 && super::super::builtins::dataset_host_keys(&b.kind, &self.dom.borrow())
139 .is_some() =>
140 {
141 super::super::builtins::dataset_host_keys(&b.kind, &self.dom.borrow())
142 .unwrap_or_default()
143 .into_iter()
144 .map(Value::str)
145 .collect()
146 }
147 _ => {
148 // for-in: キー名。for-of: 値。
149 if of {
150 b.props.values().cloned().collect()
151 } else {
152 // for-in は仕様上、自身のプロパティだけでなくプロトタイプ連鎖上の
153 // 列挙可能プロパティも辿る必要がある。以前は `b.props` (自身のみ)
154 // しか見ておらず、`Base.prototype.x=1` を継承した `new Derived()`
155 // に対する `for(k in d)` が継承プロパティを一切列挙しないバグだった。
156 // 同名キーは自身側を優先し、プロトタイプ側は1度だけ追加する。
157 // `accessors`(getter/setter 専用プロパティ)も `props` とは別
158 // マップのため、`in` 演算子の修正と同様にこちらも合わせて拾う。
159 // `Symbol.iterator` 等の well-known symbol はこの処理系では
160 // `"Symbol(...)"` という文字列キーで代用されているため
161 // (`is_symbol_like_key` 参照)、仕様どおり for-in の列挙対象
162 // から除外する。
163 let plain_keys: alloc::vec::Vec<(String, ())> = b
164 .props
165 .keys()
166 .filter(|k| !super::super::builtins::is_symbol_like_key(k))
167 .filter(|k| b.attrs.get(*k).copied().unwrap_or_default().enumerable)
168 .map(|k| (k.clone(), ()))
169 .collect();
170 let ordered_keys = super::super::builtins::spec_key_order(plain_keys);
171 let mut seen: alloc::collections::BTreeSet<String> = ordered_keys
172 .iter()
173 .map(|(k, _)| k.clone())
174 .collect();
175 let mut keys: alloc::vec::Vec<Value> = ordered_keys
176 .into_iter()
177 .map(|(k, _)| Value::str(k))
178 .collect();
179 for k in b.accessors.keys() {
180 if b.attrs.get(k).copied().unwrap_or_default().enumerable
181 && seen.insert(k.clone())
182 {
183 keys.push(Value::str(k.clone()));
184 }
185 }
186 let mut proto = b.proto.clone();
187 drop(b);
188 // `seen` はキーの重複除去のみを行い、循環プロトタイプ連鎖では
189 // ループ自体は止まらない。他の連鎖走査と同じ上限ガードで打ち切る。
190 let mut guard = 0u32;
191 while let Some(p) = proto {
192 guard += 1;
193 if guard > 1000 {
194 break;
195 }
196 let pb = p.borrow();
197 for k in pb.props.keys().filter(|k| !super::super::builtins::is_symbol_like_key(k)) {
198 if pb.attrs.get(k).copied().unwrap_or_default().enumerable
199 && seen.insert(k.clone())
200 {
201 keys.push(Value::str(k.clone()));
202 }
203 }
204 for k in pb.accessors.keys() {
205 if pb.attrs.get(k).copied().unwrap_or_default().enumerable
206 && seen.insert(k.clone())
207 {
208 keys.push(Value::str(k.clone()));
209 }
210 }
211 proto = pb.proto.clone();
212 }
213 keys
214 }
215 }
216 }
217 }
218 Value::Str(s) if of => s.chars().map(|c| Value::str(c.to_string())).collect(),
219 _ => Vec::new(),
220 }
221 }
222
223 // ============ Generator(遅延評価 / replay 駆動) ============
224
225 /// 現在 generator 本体の中断処理中か(suspend 番兵 Err を try/catch が
226 /// 捕捉しないようにするためのガード)。
227 pub(crate) fn is_suspending(&self) -> bool {
228 self.gen_replay
229 .as_ref()
230 .map(|r| r.suspending)
231 .unwrap_or(false)
232 }
233
234 /// 現在 generator が強制Returnによる巻き戻し中か。
235 pub(crate) fn is_gen_returning(&self) -> bool {
236 self.gen_replay
237 .as_ref()
238 .map(|r| r.returning.is_some())
239 .unwrap_or(false)
240 }
241
242 /// `yield value` の評価。replay 中でなければ無効(undefined)。
243 /// target 番目の yield に達したら中断(suspend 番兵 Err を返す)。
244 /// 既に通過済みの yield には保存済み resume 値を返して続行する。
245 pub(crate) fn do_yield(&mut self, value: Value) -> EvalResult {
246 let replay = match &mut self.gen_replay {
247 Some(r) => r,
248 None => return Ok(Value::Undefined),
249 };
250 let idx = replay.counter;
251 replay.counter += 1;
252 if idx < replay.target {
253 // 通過済み: `.next(v)` なら resume 値を返して続行、`.throw(e)` ならこの
254 // yield 式の位置で `e` を投げる(generator 本体の try/catch で捕捉され得る)。
255 // `.return(v)` の場合は、強制Return例外(番兵)をスローし、`finally` の実行を促す。
256 return match replay.sent.get(idx).cloned() {
257 Some(super::super::value::GenCompletion::Normal(v)) => Ok(v),
258 Some(super::super::value::GenCompletion::Throw(e)) => Err(e),
259 Some(super::super::value::GenCompletion::Return(v)) => {
260 replay.returning = Some(v);
261 let sentinel = Value::Object(Obj::host("_gen_return"));
262 Err(sentinel)
263 }
264 None => Ok(Value::Undefined),
265 };
266 }
267 // ここで中断。yield 値を記録し、suspend 番兵で最上位(resume)まで巻き戻す。
268 replay.yielded = value;
269 replay.suspending = true;
270 Err(Value::Undefined)
271 }
272
273 /// Generator を 1 ステップ進める(`.next(sent)` 相当)。
274 /// 戻り値は `(value, done)`。replay 方式で本体を先頭から再実行し、
275 /// 次の yield まで進めて中断するか、本体完了で done:true を返す。
276 pub fn generator_resume(
277 &mut self,
278 state: &Rc<RefCell<GenState>>,
279 sent: Value,
280 ) -> Result<(Value, bool), Value> {
281 self.generator_resume_inner(state, super::super::value::GenCompletion::Normal(sent))
282 }
283
284 /// `.throw(err)` 相当: 現在中断中の yield 式の位置で `err` を投げて generator を
285 /// 再開する(generator 本体の try/catch で捕捉されなければ、そのまま呼び出し元へ
286 /// 伝播する)。
287 pub fn generator_throw(
288 &mut self,
289 state: &Rc<RefCell<GenState>>,
290 err: Value,
291 ) -> Result<(Value, bool), Value> {
292 // 仕様どおり、まだ一度も `.next()` していない generator への `.throw()` は
293 // 本体を一切実行せず、そのまま例外として即座に伝播し generator を完了させる。
294 let not_started = !state.borrow().started;
295 if not_started {
296 state.borrow_mut().done = true;
297 return Err(err);
298 }
299 self.generator_resume_inner(state, super::super::value::GenCompletion::Throw(err))
300 }
301
302 /// `.return(val)` 相当: 現在中断中の yield 式の位置で return を発生させ、
303 /// try...finally ブロック等を実行して generator を再開・完了させる。
304 pub fn generator_return(
305 &mut self,
306 state: &Rc<RefCell<GenState>>,
307 val: Value,
308 ) -> Result<(Value, bool), Value> {
309 let not_started = !state.borrow().started;
310 if not_started {
311 let mut b = state.borrow_mut();
312 b.started = true;
313 b.done = true;
314 b.returned = val.clone();
315 return Ok((val, true));
316 }
317 self.generator_resume_inner(state, super::super::value::GenCompletion::Return(val))
318 }
319
320 pub(crate) fn generator_resume_inner(
321 &mut self,
322 state: &Rc<RefCell<GenState>>,
323 sent: super::super::value::GenCompletion,
324 ) -> Result<(Value, bool), Value> {
325 // 完了済みなら常に {undefined, done:true}(`.throw()` 経由なら例外をそのまま伝播)。
326 {
327 let b = state.borrow();
328 if b.done {
329 return match sent {
330 super::super::value::GenCompletion::Normal(_) => Ok((Value::Undefined, true)),
331 super::super::value::GenCompletion::Throw(e) => Err(e),
332 super::super::value::GenCompletion::Return(v) => Ok((v, true)),
333 };
334 }
335 }
336 // resume 結果を記録(最初の next の引数は捨てる)。target = 通過すべき yield 数。
337 let (func, args, this, sent_vec) = {
338 let mut b = state.borrow_mut();
339 if b.started {
340 b.sent.push(sent);
341 } else {
342 b.started = true;
343 }
344 (
345 b.func.clone(),
346 b.args.clone(),
347 b.this.clone(),
348 b.sent.clone(),
349 )
350 };
351 let target = sent_vec.len();
352
353 // 呼び出しスコープを毎回再構築(args/this は固定なので replay は決定的)。
354 let call_scope = Scope::child(func.closure.clone());
355 for (i, p) in func.params.iter().enumerate() {
356 if p.is_rest {
357 let rest_args: Vec<Value> = args.get(i..).map(|s| s.to_vec()).unwrap_or_default();
358 self.bind_pattern(
359 &p.pattern,
360 Value::Object(Obj::array(rest_args)),
361 &call_scope,
362 &this,
363 )?;
364 break;
365 }
366 let mut v = args.get(i).cloned().unwrap_or(Value::Undefined);
367 if matches!(v, Value::Undefined) {
368 if let Some(def) = &p.default {
369 v = self.eval(def, &call_scope, &this)?;
370 }
371 }
372 self.bind_pattern(&p.pattern, v, &call_scope, &this)?;
373 }
374 scope_declare(
375 &call_scope,
376 "arguments",
377 Value::Object(Obj::array(args.clone())),
378 );
379
380 // replay 状態を差し込んで本体を実行(ネスト generator は save/restore で保護)。
381 let saved = self.gen_replay.take();
382 self.gen_replay = Some(GenReplay {
383 sent: sent_vec.clone(),
384 counter: 0,
385 target,
386 suspending: false,
387 yielded: Value::Undefined,
388 returning: None,
389 });
390 let outcome = self.exec_statements(&func.body, &call_scope, &this);
391 let replay = self.gen_replay.take().unwrap_or(GenReplay {
392 sent: Vec::new(),
393 counter: 0,
394 target,
395 suspending: false,
396 yielded: Value::Undefined,
397 returning: None,
398 });
399 self.gen_replay = saved;
400
401 // ステップ予算超過は最上位まで巻き戻す(generator も例外ではない)。
402 if self.aborted {
403 return Err(Value::Undefined);
404 }
405 if replay.suspending {
406 // 中断: yield 値を返す(done:false)。状態は started/sent に保存済み。
407 return Ok((replay.yielded, false));
408 }
409
410 // 強制Returnの巻き戻しが最後まで(あるいは finally に妨げられずに)到達した場合、
411 // 且つ outcome が sentinel または正常完了(Ok)であれば、強制Returnの値を返す。
412 if let Some(v) = &replay.returning {
413 let is_sentinel = match &outcome {
414 Err(Value::Object(o)) => matches!(&o.borrow().kind, ObjKind::Host(t) if t == "_gen_return"),
415 _ => false,
416 };
417 if is_sentinel || outcome.is_ok() {
418 let mut b = state.borrow_mut();
419 b.done = true;
420 b.returned = v.clone();
421 return Ok((v.clone(), true));
422 }
423 }
424
425 // 本体が完了した(これ以上 yield しない)。done:true。
426 match outcome {
427 Ok(Completion::Return(v)) => {
428 let mut b = state.borrow_mut();
429 b.done = true;
430 b.returned = v.clone();
431 Ok((v, true))
432 }
433 Ok(_) => {
434 state.borrow_mut().done = true;
435 Ok((Value::Undefined, true))
436 }
437 Err(e) => {
438 // 本体内の throw: generator を完了扱いにして例外を伝播。
439 state.borrow_mut().done = true;
440 Err(e)
441 }
442 }
443 }
444
445 /// Generator を最後まで駆動して yield 値を Vec に集める(for-of / spread 用)。
446 /// 無限 generator はステップ予算超過(aborted)で打ち切られる。
447 pub(crate) fn drain_generator(&mut self, gen: &ObjRef) -> Vec<Value> {
448 let state = match &gen.borrow().kind {
449 ObjKind::Generator(g) => g.clone(),
450 _ => return Vec::new(),
451 };
452 let mut out = Vec::new();
453 loop {
454 if self.aborted {
455 break;
456 }
457 match self.generator_resume(&state, Value::Undefined) {
458 Ok((_, true)) => break,
459 Ok((v, false)) => out.push(v),
460 Err(_) => break,
461 }
462 }
463 out
464 }
465
466 /// イテラブルを Value 列に展開する。generator は遅延駆動する。
467 /// `iterable_values`(純関数)の generator 対応版。
468 pub fn iter_to_vec(&mut self, v: &Value) -> Vec<Value> {
469 // `iterate_values(_, true)` は Generator の専用ドライバ・ユーザー定義
470 // `[Symbol.iterator]()` カスタムイテラブル・Array/Set/Map/文字列を一通り
471 // カバーするので、スプレッド構文(`[...x]`/関数呼出の `...x`)もこれに委譲する。
472 self.iterate_values(v, true)
473 }
474
475 // ============ 式 ============
476
477}