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