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