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::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}