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    /// タイマー用の現在時刻(ミリ秒。実時刻 + 試験用の早送り分)。
152    pub(crate) fn timer_now(&self) -> u64 {
153        crate::kernel::timer::get_system_time_ms().wrapping_add(self.clock_skew.get())
154    }
155
156    /// タイマーを 1 つ実行する。`force` なら期限前でも最も早いものを実行する(同期 await の進行用)。
157    /// 期限の早い順、同じなら登録順。setInterval は呼ぶ前に次の予定を積み直す(コールバック内の
158    /// clearInterval で消せるように)。実行したら true。
159    pub(crate) fn run_timer(&mut self, force: bool) -> bool {
160        let now = self.timer_now();
161        let task = {
162            let mut q = self.macrotasks.borrow_mut();
163            let idx = q
164                .iter()
165                .enumerate()
166                .filter(|(_, t)| force || t.due_ms <= now)
167                .min_by_key(|(i, t)| (t.due_ms, *i))
168                .map(|(i, _)| i);
169            idx.and_then(|i| q.remove(i))
170        };
171        let Some(t) = task else { return false };
172        if force && t.due_ms > now {
173            // 期限前に実行する分だけ時刻を進める(後続のタイマーとの順序を保つ)。
174            self.clock_skew.set(self.clock_skew.get().wrapping_add(t.due_ms - now));
175        }
176        if let Some(p) = t.period_ms {
177            let mut next = t.clone();
178            next.due_ms = t.due_ms.max(now).wrapping_add(p.max(1));
179            self.macrotasks.borrow_mut().push_back(next);
180        }
181        let ctx = if t.period_ms.is_some() { "setInterval callback" } else { "setTimeout callback" };
182        self.call_listener(&t.cb, Value::Undefined, &t.args, ctx);
183        true
184    }
185
186    /// 互換: 期限の来たタイマーを 1 つ実行する。
187    pub(crate) fn run_one_macrotask(&mut self) -> bool {
188        self.run_timer(false)
189    }
190
191    /// 期限の来たタイマーがあるか。
192    pub fn has_due_timer(&self) -> bool {
193        let now = self.timer_now();
194        self.macrotasks.borrow().iter().any(|t| t.due_ms <= now)
195    }
196
197    /// イベントループ: マイクロタスクを消化 → 期限の来たタイマー 1 つ → 繰り返す。
198    /// `budget_ms` を使い切るか期限の来たタイマーが無くなれば戻る(残りは次の呼び出しで)。
199    pub fn run_event_loop_for(&mut self, budget_ms: u64) {
200        let start = crate::kernel::timer::get_system_time_ms();
201        loop {
202            self.run_microtasks();
203            if self.aborted {
204                break;
205            }
206            if crate::kernel::timer::get_system_time_ms().wrapping_sub(start) > budget_ms {
207                break;
208            }
209            if !self.run_timer(false) {
210                break;
211            }
212        }
213    }
214
215    /// スクリプト評価直後のイベントループ(期限の来たタイマーを最大 300ms 分)。
216    pub fn run_event_loop(&mut self) {
217        self.run_event_loop_for(300);
218    }
219
220    /// await: 値が Promise ならマイクロタスクを駆動して解決まで進め、値を返す(reject は throw)。
221    /// `using` の複数 dispose が例外を投げた場合に、新しい例外(`new_err`)と既存の
222    /// 保留中の例外(`prev`)を `SuppressedError` へ集約する。`prev` が無ければ `new_err` を
223    /// そのまま返す(グローバルに `SuppressedError` が無い異常系でも `new_err` へ安全にフォールバック)。
224    pub(crate) fn chain_suppressed(&mut self, prev: Option<Value>, new_err: Value) -> Value {
225        let Some(suppressed) = prev else {
226            return new_err;
227        };
228        let Some(ctor) = scope_get(&self.global, "SuppressedError") else {
229            return new_err;
230        };
231        self.call_value(&ctor, Value::Undefined, &[new_err.clone(), suppressed, Value::str("")])
232            .unwrap_or(new_err)
233    }
234
235    pub(crate) fn await_value(&mut self, v: Value) -> EvalResult {
236        let state = match &v {
237            Value::Object(o) => match &o.borrow().kind {
238                ObjKind::PromiseObj(s) => Some(s.clone()),
239                _ => None,
240            },
241            _ => None,
242        };
243        // **重要**: `await` の仕様(Await 抽象操作は内部で PromiseResolve を呼ぶ)どおり、
244        // 本物の Promise 以外の値(`.then` を持つ汎用 thenable を含む)も
245        // `Promise.resolve()` と同じ経路に通す必要があるが、以前はここで即座に値を
246        // そのまま返しており、`await { then(resolve){...} }` が `.then` を一切呼ばず
247        // オブジェクト自体を結果にしてしまうバグだった(`Promise.resolve(thenable)`
248        // 経由なら動くのに `await thenable` 直書きだけ非対称だった)。
249        let state = match state {
250            Some(s) => s,
251            None => {
252                let new_state = Rc::new(RefCell::new(PromiseState::pending()));
253                self.promise_resolve(&new_state, v);
254                new_state
255            }
256        };
257        loop {
258            let status = state.borrow().status;
259            match status {
260                PromiseStatus::Fulfilled => return Ok(state.borrow().value.clone()),
261                PromiseStatus::Rejected => return Err(state.borrow().value.clone()),
262                PromiseStatus::Pending => {
263                    if self.aborted {
264                        return Err(Value::Undefined);
265                    }
266                    // マイクロ → タイマーの順で進める。この処理系の await は同期実行なので、期限前の
267                    // タイマーも時刻を早送りして実行する。すべて空なら解決不能。
268                    let has_micro = self.run_one_microtask();
269                    let has_macro = !has_micro && self.run_timer(true);
270                    if !has_micro && !has_macro {
271                        return Ok(Value::Undefined);
272                    }
273                }
274            }
275        }
276    }
277
278}