Skip to main content

atmos/os_lib/js/interp/
promise_loop.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    /// Promise を解決する。値が Promise/thenable なら採用(チェーン)する。
8    pub fn promise_resolve(&mut self, state: &Rc<RefCell<PromiseState>>, value: Value) {
9        if state.borrow().status != PromiseStatus::Pending {
10            return;
11        }
12        // Promise の採用: 内側が settle したら自身も settle。
13        if let Value::Object(o) = &value {
14            let inner = match &o.borrow().kind {
15                ObjKind::PromiseObj(s) => Some(s.clone()),
16                _ => None,
17            };
18            if let Some(inner) = inner {
19                let on_f = Value::Object(Obj::resolver(state.clone(), false));
20                let on_r = Value::Object(Obj::resolver(state.clone(), true));
21                self.promise_then(&inner, Some(on_f), Some(on_r));
22                return;
23            }
24        }
25        // **重要**: 汎用 thenable(本物の Promise ではないが、呼び出し可能な `.then`
26        // メソッドを持つ任意のオブジェクト。古いライブラリの独自 Promise 実装や
27        // `{ then(resolve){ resolve(1) } }` のような手書きの thenable でよく使われる)
28        // の同化(assimilation)が丸ごと未対応で、`Promise.resolve(thenable)`/
29        // `await thenable` がそのオブジェクト自体を履行値にしてしまい、`.then` を
30        // 一切呼ばずに終わっていたバグ。仕様どおり `thenable.then(resolve, reject)`
31        // を呼び、その中での resolve/reject 呼び出しで自身を settle させる。
32        if matches!(&value, Value::Object(_)) {
33            // `o.borrow().props.get("then")` は own プロパティしか見ないため、
34            // `class MyThenable { then(resolve){...} }` のようにメソッドが
35            // `.prototype` 側にあるクラスインスタンスの thenable を取りこぼす
36            // バグだった(自己検証で発見)。プロトタイプ連鎖を辿る通常のプロパティ
37            // 解決 `get_property` を使う。
38            let then_fn = self.get_property(&value, "then").unwrap_or(Value::Undefined);
39            if matches!(&then_fn, Value::Object(f) if f.borrow().is_callable()) {
40                let on_f = Value::Object(Obj::resolver(state.clone(), false));
41                let on_r = Value::Object(Obj::resolver(state.clone(), true));
42                if let Err(e) = self.call_value(&then_fn, value.clone(), &[on_f, on_r]) {
43                    // thenable.then() 呼出し自体が例外を投げた場合は仕様どおり拒否。
44                    self.promise_reject(state, e);
45                }
46                return;
47            }
48        }
49        let reactions = {
50            let mut b = state.borrow_mut();
51            b.status = PromiseStatus::Fulfilled;
52            b.value = value.clone();
53            core::mem::take(&mut b.reactions)
54        };
55        for r in &reactions {
56            self.schedule_reaction(r, value.clone(), true);
57        }
58    }
59
60    /// Promise を拒否する。
61    pub fn promise_reject(&mut self, state: &Rc<RefCell<PromiseState>>, reason: Value) {
62        if state.borrow().status != PromiseStatus::Pending {
63            return;
64        }
65        let reactions = {
66            let mut b = state.borrow_mut();
67            b.status = PromiseStatus::Rejected;
68            b.value = reason.clone();
69            core::mem::take(&mut b.reactions)
70        };
71        for r in &reactions {
72            self.schedule_reaction(r, reason.clone(), false);
73        }
74    }
75
76    /// then 反応を登録し、派生 Promise を返す。
77    pub fn promise_then(
78        &mut self,
79        state: &Rc<RefCell<PromiseState>>,
80        on_fulfilled: Option<Value>,
81        on_rejected: Option<Value>,
82    ) -> Value {
83        let result = Rc::new(RefCell::new(PromiseState::pending()));
84        let reaction = Reaction {
85            on_fulfilled,
86            on_rejected,
87            result: result.clone(),
88        };
89        let status = state.borrow().status;
90        match status {
91            PromiseStatus::Pending => state.borrow_mut().reactions.push(reaction),
92            PromiseStatus::Fulfilled => {
93                let v = state.borrow().value.clone();
94                self.schedule_reaction(&reaction, v, true);
95            }
96            PromiseStatus::Rejected => {
97                let v = state.borrow().value.clone();
98                self.schedule_reaction(&reaction, v, false);
99            }
100        }
101        Value::Object(Obj::promise(result))
102    }
103
104    pub(crate) fn schedule_reaction(&self, reaction: &Reaction, value: Value, is_fulfill: bool) {
105        let handler = if is_fulfill {
106            reaction.on_fulfilled.clone()
107        } else {
108            reaction.on_rejected.clone()
109        };
110        self.microtasks.borrow_mut().push_back(Job {
111            handler,
112            arg: value,
113            is_fulfill,
114            result: reaction.result.clone(),
115        });
116    }
117
118    /// マイクロタスクを 1 つ実行。実行したら true。
119    pub(crate) fn run_one_microtask(&mut self) -> bool {
120        let job = self.microtasks.borrow_mut().pop_front();
121        let job = match job {
122            Some(j) => j,
123            None => return false,
124        };
125        match job.handler {
126            Some(h) => match self.call_value(&h, Value::Undefined, &[job.arg]) {
127                Ok(v) => self.promise_resolve(&job.result, v),
128                Err(e) => {
129                    if !self.aborted {
130                        self.promise_reject(&job.result, e);
131                    }
132                }
133            },
134            None => {
135                if job.is_fulfill {
136                    self.promise_resolve(&job.result, job.arg);
137                } else {
138                    self.promise_reject(&job.result, job.arg);
139                }
140            }
141        }
142        true
143    }
144
145    /// 保留中のマイクロタスクを全て消化する。
146    pub fn run_microtasks(&mut self) {
147        while !self.aborted && self.run_one_microtask() {}
148    }
149
150    /// setTimeout コールバック(マクロタスク)を 1 つ実行。実行したら true。
151    pub(crate) fn run_one_macrotask(&mut self) -> bool {
152        let task = self.macrotasks.borrow_mut().pop_front();
153        let (cb, args, _id) = match task {
154            Some(t) => t,
155            None => return false,
156        };
157        // setTimeout コールバック内の例外も捨てない(従来は完全に消えていた)。
158        self.call_listener(&cb, Value::Undefined, &args, "setTimeout callback");
159        true
160    }
161
162    /// setInterval コールバックを発火し、残回数をデクリメント。全完了なら true。
163    pub(crate) fn run_intervals(&mut self) -> bool {
164        if self.intervals.is_empty() {
165            return false;
166        }
167        let ids: Vec<u64> = self.intervals.iter().map(|(id, _, _, _)| *id).collect();
168        for id in ids {
169            let entry = self.intervals.iter().position(|(i, _, _, _)| *i == id);
170            if let Some(pos) = entry {
171                let (_, cb, args, remaining) = self.intervals[pos].clone();
172                if remaining == 0 {
173                    self.intervals.remove(pos);
174                    continue;
175                }
176                self.intervals[pos].3 -= 1;
177                self.call_listener(&cb, Value::Undefined, &args, "setInterval callback");
178            }
179        }
180        self.intervals.iter().any(|(_, _, _, r)| *r > 0)
181    }
182
183    /// イベントループ: マイクロタスクを消化 → マクロタスク 1 つ → インターバル → 繰り返す。
184    pub fn run_event_loop(&mut self) {
185        loop {
186            self.run_microtasks();
187            if self.aborted {
188                break;
189            }
190            let has_macro = self.run_one_macrotask();
191            let has_interval = self.run_intervals();
192            if !has_macro && !has_interval {
193                break;
194            }
195        }
196    }
197
198    /// await: 値が Promise ならマイクロタスクを駆動して解決まで進め、値を返す(reject は throw)。
199    /// `using` の複数 dispose が例外を投げた場合に、新しい例外(`new_err`)と既存の
200    /// 保留中の例外(`prev`)を `SuppressedError` へ集約する。`prev` が無ければ `new_err` を
201    /// そのまま返す(グローバルに `SuppressedError` が無い異常系でも `new_err` へ安全にフォールバック)。
202    pub(crate) fn chain_suppressed(&mut self, prev: Option<Value>, new_err: Value) -> Value {
203        let Some(suppressed) = prev else {
204            return new_err;
205        };
206        let Some(ctor) = scope_get(&self.global, "SuppressedError") else {
207            return new_err;
208        };
209        self.call_value(&ctor, Value::Undefined, &[new_err.clone(), suppressed, Value::str("")])
210            .unwrap_or(new_err)
211    }
212
213    pub(crate) fn await_value(&mut self, v: Value) -> EvalResult {
214        let state = match &v {
215            Value::Object(o) => match &o.borrow().kind {
216                ObjKind::PromiseObj(s) => Some(s.clone()),
217                _ => None,
218            },
219            _ => None,
220        };
221        // **重要**: `await` の仕様(Await 抽象操作は内部で PromiseResolve を呼ぶ)どおり、
222        // 本物の Promise 以外の値(`.then` を持つ汎用 thenable を含む)も
223        // `Promise.resolve()` と同じ経路に通す必要があるが、以前はここで即座に値を
224        // そのまま返しており、`await { then(resolve){...} }` が `.then` を一切呼ばず
225        // オブジェクト自体を結果にしてしまうバグだった(`Promise.resolve(thenable)`
226        // 経由なら動くのに `await thenable` 直書きだけ非対称だった)。
227        let state = match state {
228            Some(s) => s,
229            None => {
230                let new_state = Rc::new(RefCell::new(PromiseState::pending()));
231                self.promise_resolve(&new_state, v);
232                new_state
233            }
234        };
235        loop {
236            let status = state.borrow().status;
237            match status {
238                PromiseStatus::Fulfilled => return Ok(state.borrow().value.clone()),
239                PromiseStatus::Rejected => return Err(state.borrow().value.clone()),
240                PromiseStatus::Pending => {
241                    if self.aborted {
242                        return Err(Value::Undefined);
243                    }
244                    // マイクロ→マクロ→インターバルの順で進める。すべて空なら解決不能。
245                    let has_micro = self.run_one_microtask();
246                    let has_macro = self.run_one_macrotask();
247                    let has_interval = self.run_intervals();
248                    if !has_micro && !has_macro && !has_interval {
249                        return Ok(Value::Undefined);
250                    }
251                }
252            }
253        }
254    }
255
256}