Skip to main content

atmos/os_lib/js/builtins/
timers_gen.rs

1// 分割: builtins.rs より機械的に移動(2026-07-16 リファクタ フェーズ2)。
2// ロジック不変。可視性のみ pub(crate) へ昇格し、親が pub(crate) use で再エクスポート。
3use super::*;
4
5// ============ タイマー ============
6
7pub(crate) static TIMER_ID: AtomicU64 = AtomicU64::new(1);
8
9pub(crate) fn set_timeout(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
10    if let Some(cb) = callable_or_none(arg(a, 0)) {
11        let extra: Vec<Value> = if a.len() > 2 {
12            a[2..].to_vec()
13        } else {
14            Vec::new()
15        };
16        let id = TIMER_ID.fetch_add(1, Ordering::Relaxed);
17        it.macrotasks.borrow_mut().push_back((cb, extra, id));
18        return Ok(Value::Number(id as f64));
19    }
20    Ok(Value::Number(0.0))
21}
22
23/// setInterval: コールバックを最大 200 回発火(bare-metal ループ無限防止。
24/// `run_intervals`は`remaining`が尽きるかeval完了まで進む有限ループのため、
25/// 上限を上げても無限ループにはならない)。以前は上限8回だったため、
26/// 実サイト www.sugi-lab.net の統計カウンターアニメーション(`increment =
27/// target/100`を約100回積み上げて最終値へ到達する定番パターン。
28/// `.stat-number`の"10+"/"50+"/"200+"表示)が最終値の8%程度で頭打ちになり
29/// 正しい数値へ到達できないバグだった(2026-07-22発見・修正)。
30pub(crate) fn set_interval(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
31    if let Some(cb) = callable_or_none(arg(a, 0)) {
32        let extra: Vec<Value> = if a.len() > 2 {
33            a[2..].to_vec()
34        } else {
35            Vec::new()
36        };
37        let id = TIMER_ID.fetch_add(1, Ordering::Relaxed);
38        it.intervals.push((id, cb, extra, 200));
39        return Ok(Value::Number(id as f64));
40    }
41    Ok(Value::Number(0.0))
42}
43
44pub(crate) fn clear_interval(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
45    let id = arg(a, 0).to_number() as u64;
46    it.intervals.retain(|(i, _, _, _)| *i != id);
47    Ok(Value::Undefined)
48}
49
50pub(crate) fn clear_timeout(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
51    let id = arg(a, 0).to_number() as u64;
52    it.macrotasks.borrow_mut().retain(|(_, _, tid)| *tid != id);
53    Ok(Value::Undefined)
54}
55
56/// 疑似 DOMHighResTimeStamp(16ms 刻みの単調増加)。決定論的にするため実時刻は使わない。
57pub(crate) static RAF_TS: AtomicU64 = AtomicU64::new(0);
58
59/// requestAnimationFrame(cb): 次のイベントループでコールバックを実行(timestamp を引数に渡す)。
60/// setTimeout と同じマクロタスク機構に乗せるため cancelAnimationFrame は clearTimeout と共通。
61pub(crate) fn request_animation_frame(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
62    if let Some(cb) = callable_or_none(arg(a, 0)) {
63        let ts = RAF_TS.fetch_add(16, Ordering::Relaxed) as f64;
64        let id = TIMER_ID.fetch_add(1, Ordering::Relaxed);
65        it.macrotasks
66            .borrow_mut()
67            .push_back((cb, alloc::vec![Value::Number(ts)], id));
68        return Ok(Value::Number(id as f64));
69    }
70    Ok(Value::Number(0.0))
71}
72
73pub(crate) fn queue_microtask(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
74    if let Some(cb) = callable_or_none(arg(a, 0)) {
75        let result = new_pending();
76        it.microtasks.borrow_mut().push_back(Job {
77            handler: Some(cb),
78            arg: Value::Undefined,
79            is_fulfill: true,
80            result,
81        });
82    }
83    Ok(Value::Undefined)
84}
85
86// ============ Generator ============
87
88/// `next`/`return` メソッド(interp の get_property から返す)。
89pub fn generator_method(key: &str) -> Value {
90    match key {
91        "next" => nv("Generator.next", gen_next),
92        "return" => nv("Generator.return", gen_return),
93        "throw" => nv("Generator.throw", gen_throw),
94        // Iterator helpers(ES2025)。本来は遅延評価(無限イテレータにも対応)だが、
95        // この処理系には汎用の遅延イテレータラッパー型が無いため、generator を
96        // その場で全展開してから処理する簡略実装(無限 generator は非対応)。
97        // map/filter/flatMap は Array を返すため、以降は既存の Array.prototype
98        // メソッドでそのままチェーンできる。
99        "map" => nv("Iterator.map", iter_help_map),
100        "filter" => nv("Iterator.filter", iter_help_filter),
101        "take" => nv("Iterator.take", iter_help_take),
102        "drop" => nv("Iterator.drop", iter_help_drop),
103        "flatMap" => nv("Iterator.flatMap", iter_help_flat_map),
104        "toArray" => nv("Iterator.toArray", iter_help_to_array),
105        "forEach" => nv("Iterator.forEach", iter_help_for_each),
106        "some" => nv("Iterator.some", iter_help_some),
107        "every" => nv("Iterator.every", iter_help_every),
108        "find" => nv("Iterator.find", iter_help_find),
109        "reduce" => nv("Iterator.reduce", iter_help_reduce),
110        _ => Value::Undefined,
111    }
112}
113
114pub(crate) fn iter_help_drain(it: &mut Interp, this: &Value) -> Vec<Value> {
115    it.iter_to_vec(this)
116}
117
118/// `Iterator.from(iterable)`(ES2025)。任意のイテラブル(配列/Set/Map/Generator/文字列)を
119/// 即座に展開して ObjKind::Array でラップし、Iterator helpers 一式にアクセスできるようにする。
120/// `map`/`filter`/`flatMap`/`forEach`/`some`/`every`/`find`/`reduce` は Array.prototype の
121/// 同名メソッドが(このプロパティルックアップでは配列の組込みメソッド判定が `.props` より
122/// 先に評価されるため)そのまま使われ、`take`/`drop`/`toArray`(Array に無いメソッド)のみを
123/// `.props` として追加する。Generator と同じ「その場で全展開する」簡略実装(無限イテレータ非対応)。
124/// `take`/`drop`(ES2025 Iterator Helpers)が返す新しい配列オブジェクトへ、
125/// 同じヘルパーメソッド一式を再付与する。以前は`Iterator.from(...)`が返す
126/// 最初のオブジェクトにしかこれらのメソッドが付与されておらず、`.take(n)`/
127/// `.drop(n)`自身が返す新しい配列オブジェクトには引き継がれないため、
128/// `Iterator.from([...]).take(2).toArray()`のような定番のチェーン呼び出しが
129/// 2段目のメソッド呼び出しで「not a function」になって失敗するバグだった。
130pub(crate) fn attach_iterator_helpers(obj: &super::super::value::ObjRef) {
131    let mut b = obj.borrow_mut();
132    b.props.insert("map".into(), nv("Iterator.map", iter_help_map));
133    b.props.insert("filter".into(), nv("Iterator.filter", iter_help_filter));
134    b.props.insert("take".into(), nv("Iterator.take", iter_help_take));
135    b.props.insert("drop".into(), nv("Iterator.drop", iter_help_drop));
136    b.props.insert("flatMap".into(), nv("Iterator.flatMap", iter_help_flat_map));
137    b.props.insert("toArray".into(), nv("Iterator.toArray", iter_help_to_array));
138    b.props.insert("forEach".into(), nv("Iterator.forEach", iter_help_for_each));
139    b.props.insert("some".into(), nv("Iterator.some", iter_help_some));
140    b.props.insert("every".into(), nv("Iterator.every", iter_help_every));
141    b.props.insert("find".into(), nv("Iterator.find", iter_help_find));
142    b.props.insert("reduce".into(), nv("Iterator.reduce", iter_help_reduce));
143}
144
145pub(crate) fn iterator_from(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
146    let source = arg(a, 0);
147    let items = it.iter_to_vec(&source);
148    let obj = Obj::array(items);
149    attach_iterator_helpers(&obj);
150    Ok(Value::Object(obj))
151}
152
153/// `Iterator.range(start, end, step?)`(ES2025 Standard)。数値の範囲シーケンスを生成する。
154pub(crate) fn iterator_range(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
155    let start = arg(a, 0).to_number();
156    let end = arg(a, 1).to_number();
157    if start.is_nan() || end.is_nan() {
158        return Err(Value::str("RangeError: start and end must be numbers"));
159    }
160    let step = if a.len() > 2 && !matches!(a[2], Value::Undefined) {
161        a[2].to_number()
162    } else if start <= end {
163        1.0
164    } else {
165        -1.0
166    };
167    if step == 0.0 || step.is_nan() {
168        return Err(Value::str("RangeError: step cannot be zero or NaN"));
169    }
170
171    let mut items = Vec::new();
172    let mut current = start;
173    if step > 0.0 {
174        while current < end {
175            items.push(Value::Number(current));
176            current += step;
177        }
178    } else {
179        while current > end {
180            items.push(Value::Number(current));
181            current += step;
182        }
183    }
184
185    let obj = Obj::array(items);
186    attach_iterator_helpers(&obj);
187    Ok(Value::Object(obj))
188}
189pub(crate) fn iter_help_map(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
190    let cb = arg(a, 0);
191    let items = iter_help_drain(it, &this);
192    let mut out = Vec::with_capacity(items.len());
193    for (idx, v) in items.into_iter().enumerate() {
194        out.push(it.call_value(&cb, Value::Undefined, &[v, Value::Number(idx as f64)])?);
195    }
196    let obj = Obj::array(out);
197    attach_iterator_helpers(&obj);
198    Ok(Value::Object(obj))
199}
200pub(crate) fn iter_help_filter(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
201    let cb = arg(a, 0);
202    let items = iter_help_drain(it, &this);
203    let mut out = Vec::new();
204    for (idx, v) in items.into_iter().enumerate() {
205        if it
206            .call_value(&cb, Value::Undefined, &[v.clone(), Value::Number(idx as f64)])?
207            .truthy()
208        {
209            out.push(v);
210        }
211    }
212    let obj = Obj::array(out);
213    attach_iterator_helpers(&obj);
214    Ok(Value::Object(obj))
215}
216pub(crate) fn iter_help_take(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
217    let n = arg(a, 0).to_number().max(0.0) as usize;
218    let items = iter_help_drain(it, &this);
219    let obj = Obj::array(items.into_iter().take(n).collect());
220    attach_iterator_helpers(&obj);
221    Ok(Value::Object(obj))
222}
223pub(crate) fn iter_help_drop(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
224    let n = arg(a, 0).to_number().max(0.0) as usize;
225    let items = iter_help_drain(it, &this);
226    let obj = Obj::array(items.into_iter().skip(n).collect());
227    attach_iterator_helpers(&obj);
228    Ok(Value::Object(obj))
229}
230pub(crate) fn iter_help_flat_map(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
231    let cb = arg(a, 0);
232    let items = iter_help_drain(it, &this);
233    let mut out = Vec::new();
234    for (idx, v) in items.into_iter().enumerate() {
235        let mapped = it.call_value(&cb, Value::Undefined, &[v, Value::Number(idx as f64)])?;
236        out.extend(it.iter_to_vec(&mapped));
237    }
238    let obj = Obj::array(out);
239    attach_iterator_helpers(&obj);
240    Ok(Value::Object(obj))
241}
242pub(crate) fn iter_help_to_array(it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
243    Ok(Value::Object(Obj::array(iter_help_drain(it, &this))))
244}
245pub(crate) fn iter_help_for_each(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
246    let cb = arg(a, 0);
247    let items = iter_help_drain(it, &this);
248    for (idx, v) in items.into_iter().enumerate() {
249        it.call_value(&cb, Value::Undefined, &[v, Value::Number(idx as f64)])?;
250    }
251    Ok(Value::Undefined)
252}
253pub(crate) fn iter_help_some(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
254    let cb = arg(a, 0);
255    let items = iter_help_drain(it, &this);
256    for (idx, v) in items.into_iter().enumerate() {
257        if it
258            .call_value(&cb, Value::Undefined, &[v, Value::Number(idx as f64)])?
259            .truthy()
260        {
261            return Ok(Value::Bool(true));
262        }
263    }
264    Ok(Value::Bool(false))
265}
266pub(crate) fn iter_help_every(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
267    let cb = arg(a, 0);
268    let items = iter_help_drain(it, &this);
269    for (idx, v) in items.into_iter().enumerate() {
270        if !it
271            .call_value(&cb, Value::Undefined, &[v, Value::Number(idx as f64)])?
272            .truthy()
273        {
274            return Ok(Value::Bool(false));
275        }
276    }
277    Ok(Value::Bool(true))
278}
279pub(crate) fn iter_help_find(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
280    let cb = arg(a, 0);
281    let items = iter_help_drain(it, &this);
282    for (idx, v) in items.into_iter().enumerate() {
283        if it
284            .call_value(&cb, Value::Undefined, &[v.clone(), Value::Number(idx as f64)])?
285            .truthy()
286        {
287            return Ok(v);
288        }
289    }
290    Ok(Value::Undefined)
291}
292pub(crate) fn iter_help_reduce(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
293    let cb = arg(a, 0);
294    let items = iter_help_drain(it, &this);
295    let mut iter = items.into_iter().enumerate();
296    let mut acc = if a.len() > 1 {
297        arg(a, 1)
298    } else {
299        match iter.next() {
300            Some((_, v)) => v,
301            None => {
302                return Err(it.error(String::from("Reduce of empty iterator with no initial value")))
303            }
304        }
305    };
306    for (idx, v) in iter {
307        acc = it.call_value(&cb, Value::Undefined, &[acc, v, Value::Number(idx as f64)])?;
308    }
309    Ok(acc)
310}
311
312pub(crate) fn gen_state(this: &Value) -> Option<PromiseRc<PromiseRefCell<GenState>>> {
313    if let Value::Object(o) = this {
314        let o = unwrap_proxy_target(o);
315        let b = o.borrow();
316        if let ObjKind::Generator(g) = &b.kind {
317            return Some(g.clone());
318        }
319    }
320    None
321}
322
323pub(crate) fn iter_result(value: Value, done: bool) -> Value {
324    let res = Obj::plain();
325    res.borrow_mut().props.insert("value".into(), value);
326    res.borrow_mut()
327        .props
328        .insert("done".into(), Value::Bool(done));
329    Value::Object(res)
330}
331
332/// `async function* () {}`(非同期 generator)の `.next()` が仕様上必ず Promise を
333/// 返すべきところ(`AsyncGenerator.prototype.next`)、`is_async` フラグが `is_
334/// generator` のチェックに常に先を越されて完全に無視されており(`call_value` の
335/// 分岐順序)、普通の同期 generator と全く同じ `{value,done}` プレーンオブジェクトを
336/// 直接返してしまっていたバグ。`await gen.next()` は非 Promise 値をそのまま返す
337/// 簡略実装のおかげで見かけ上は動いていたが、`gen.next() instanceof Promise` 等の
338/// 型チェックは常に false になっていた。
339pub(crate) fn gen_next(i: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
340    if let Some(g) = gen_state(&this) {
341        let is_async = g.borrow().func.is_async;
342        let sent = arg(a, 0);
343        let result = i.generator_resume(&g, sent);
344        if is_async {
345            return Ok(match result {
346                Ok((value, done)) => resolved_promise(i, iter_result(value, done)),
347                Err(e) => rejected_promise(i, e),
348            });
349        }
350        let (value, done) = result?;
351        return Ok(iter_result(value, done));
352    }
353    Ok(iter_result(Value::Undefined, true))
354}
355
356/// `Generator.prototype[Symbol.iterator]`/`AsyncGenerator.prototype[Symbol.asyncIterator]`
357/// は仕様上どちらも「自分自身を返す」だけだが、丸ごと未登録だったため
358/// `for await (x of asyncGen())` が `Symbol.asyncIterator` を見つけられず、
359/// 常に同期の eager-drain フォールバック(`iterate_values`/`drain_generator`)に
360/// 落ちていた(値自体は一致するが、generator 内で投げた例外が for-await に
361/// 伝播せず黙って握り潰される差異があった)。
362pub(crate) fn gen_self_iterator(_: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
363    Ok(this)
364}
365
366pub fn gen_self_iterator_fn() -> Value {
367    nv("Generator[Symbol.iterator]", gen_self_iterator)
368}
369
370pub(crate) fn gen_return(i: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
371    let v = arg(a, 0);
372    if let Some(g) = gen_state(&this) {
373        let is_async = g.borrow().func.is_async;
374        let result = i.generator_return(&g, v.clone());
375        if is_async {
376            return Ok(match result {
377                Ok((value, done)) => resolved_promise(i, iter_result(value, done)),
378                Err(e) => rejected_promise(i, e),
379            });
380        }
381        let (value, done) = result?;
382        return Ok(iter_result(value, done));
383    }
384    Ok(iter_result(v, true))
385}
386/// `generator.throw(err)`(ES2015)が丸ごと未実装だった。`next`/`return` はあったが、
387/// `throw` だけが欠落していたため、generator の中断位置に例外を注入する(協調的な
388/// キャンセルや `for await` の内部実装等で使われる)標準的な操作ができなかった。
389pub(crate) fn gen_throw(i: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
390    let err = arg(a, 0);
391    if let Some(g) = gen_state(&this) {
392        let (value, done) = i.generator_throw(&g, err)?;
393        return Ok(iter_result(value, done));
394    }
395    // generator でなければ(本来あり得ないが)そのまま投げ返す。
396    Err(err)
397}
398