Skip to main content

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}