Skip to main content

atmos/os_lib/js/builtins/
extra_methods.rs

1// 分割: builtins.rs より機械的に移動(2026-07-16 リファクタ フェーズ2)。
2// ロジック不変。可視性のみ pub(crate) へ昇格し、親が pub(crate) use で再エクスポート。
3use super::*;
4
5// ===== 追加の Array メソッド =====
6pub(crate) fn arr_at(it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
7    let items = generic_array_items(it, &t);
8    let n = arg(a, 0).to_number() as i64;
9    let len = items.len() as i64;
10    let idx = if n < 0 { len + n } else { n };
11    if idx >= 0 && idx < len {
12        Ok(items[idx as usize].clone())
13    } else {
14        Ok(Value::Undefined)
15    }
16}
17pub(crate) fn arr_find_last(it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
18    let items = generic_array_items(it, &t);
19    let f = arg(a, 0);
20    let this_arg = arg(a, 1);
21    for i in (0..items.len()).rev() {
22        if it
23            .call_value(
24                &f,
25                this_arg.clone(),
26                &[items[i].clone(), Value::Number(i as f64), t.clone()],
27            )?
28            .truthy()
29        {
30            return Ok(items[i].clone());
31        }
32    }
33    Ok(Value::Undefined)
34}
35pub(crate) fn arr_find_last_index(it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
36    let items = generic_array_items(it, &t);
37    let f = arg(a, 0);
38    let this_arg = arg(a, 1);
39    for i in (0..items.len()).rev() {
40        if it
41            .call_value(
42                &f,
43                this_arg.clone(),
44                &[items[i].clone(), Value::Number(i as f64), t.clone()],
45            )?
46            .truthy()
47        {
48            return Ok(Value::Number(i as f64));
49        }
50    }
51    Ok(Value::Number(-1.0))
52}
53pub(crate) fn arr_flat_map(it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
54    let items = generic_array_items(it, &t);
55    let f = arg(a, 0);
56    let this_arg = arg(a, 1);
57    let mut out: Vec<Value> = Vec::new();
58    for (i, v) in items.iter().enumerate() {
59        let r = it.call_value(
60            &f,
61            this_arg.clone(),
62            &[v.clone(), Value::Number(i as f64), t.clone()],
63        )?;
64        let inner = if let Value::Object(o) = &r {
65            if let ObjKind::Array(items) = &o.borrow().kind {
66                Some(items.clone())
67            } else {
68                None
69            }
70        } else {
71            None
72        };
73        match inner {
74            Some(arr) => out.extend(arr),
75            None => out.push(r),
76        }
77    }
78    let a_obj = array_species_create(it, &t, 0)?;
79    populate_array_species(it, &a_obj, out)
80}
81/// `entries`/`keys`/`values` が返すべき本物の Iterator オブジェクト(`.next()`/
82/// `[Symbol.iterator]` を持つ)を、`Obj::host("iterator")` + 内部プロパティ
83/// `_items`/`_pos` で近似する(`ObjKind` に新しい variant を追加すると全 exhaustive match
84/// への波及が大きいため、既存の Host タグ機構に乗せる軽量な実装)。以前は単なる配列を
85/// 返しており、`for...of`(配列自体が for-of 可能なため気づかれなかった)は動くが
86/// `const it = arr.values(); it.next()` のような明示的なイテレータプロトコル駆動が
87/// 「`next` が存在しない」で壊れていた。
88pub fn make_iterator(items: Vec<Value>) -> super::super::value::ObjRef {
89    let o = Obj::host("iterator");
90    o.borrow_mut().props.insert("_items".into(), Value::Object(Obj::array(items)));
91    o.borrow_mut().props.insert("_pos".into(), Value::Number(0.0));
92    o
93}
94pub fn iterator_next(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
95    if let Value::Object(o) = &this {
96        let items = o.borrow().props.get("_items").cloned();
97        let pos = o
98            .borrow()
99            .props
100            .get("_pos")
101            .map(|v| v.to_number() as usize)
102            .unwrap_or(0);
103        if let Some(Value::Object(arr)) = items {
104            let item = if let ObjKind::Array(v) = &arr.borrow().kind {
105                v.get(pos).cloned()
106            } else {
107                None
108            };
109            if let Some(value) = item {
110                o.borrow_mut().props.insert("_pos".into(), Value::Number((pos + 1) as f64));
111                return Ok(iter_result(value, false));
112            }
113        }
114    }
115    Ok(iter_result(Value::Undefined, true))
116}
117pub fn iterator_self(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
118    Ok(this)
119}
120/// `make_iterator()` の残り要素(`_pos` 以降)を取り出し、消費済みにする(`_pos` を末尾へ
121/// 進める)。Iterator Helpers(ES2025: `map`/`filter`/`take`/`drop`/`toArray`/`forEach`/
122/// `reduce`)用の共通ヘルパ。仕様上これらは遅延評価(要素を1つずつ必要な分だけ取り出す)
123/// だが、本エンジンの軽量イテレータ表現(`_items`/`_pos` を持つ `Obj::host("iterator")`)
124/// では、呼び出し時点で残り要素をまとめて処理する即時評価で近似する(無限イテレータの
125/// `take` 等、遅延性に依存するケースは非対応。他の組込み簡略化と同種の割り切り)。
126pub(crate) fn iterator_remaining(this: &Value) -> Vec<Value> {
127    if let Value::Object(o) = this {
128        let items = o.borrow().props.get("_items").cloned();
129        let pos = o
130            .borrow()
131            .props
132            .get("_pos")
133            .map(|v| v.to_number() as usize)
134            .unwrap_or(0);
135        if let Some(Value::Object(arr)) = items {
136            let rest: Option<Vec<Value>> = if let ObjKind::Array(v) = &arr.borrow().kind {
137                Some(v.iter().skip(pos).cloned().collect())
138            } else {
139                None
140            };
141            if let Some(rest) = rest {
142                let len = if let ObjKind::Array(v) = &arr.borrow().kind { v.len() } else { pos };
143                o.borrow_mut().props.insert("_pos".into(), Value::Number(len as f64));
144                return rest;
145            }
146        }
147    }
148    Vec::new()
149}
150/// `Iterator.prototype.map(fn)`(ES2025 Iterator Helpers)。
151pub fn iterator_map(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
152    let cb = arg(a, 0);
153    let items = iterator_remaining(&this);
154    let mut out = Vec::with_capacity(items.len());
155    for (i, v) in items.into_iter().enumerate() {
156        out.push(it.call_value(&cb, Value::Undefined, &[v, Value::Number(i as f64)])?);
157    }
158    Ok(Value::Object(make_iterator(out)))
159}
160/// `Iterator.prototype.filter(fn)`(ES2025)。
161pub fn iterator_filter(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
162    let cb = arg(a, 0);
163    let items = iterator_remaining(&this);
164    let mut out = Vec::new();
165    for (i, v) in items.into_iter().enumerate() {
166        let keep = it.call_value(&cb, Value::Undefined, &[v.clone(), Value::Number(i as f64)])?;
167        if keep.truthy() {
168            out.push(v);
169        }
170    }
171    Ok(Value::Object(make_iterator(out)))
172}
173/// `Iterator.prototype.take(n)`(ES2025)。
174pub fn iterator_take(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
175    let n = arg(a, 0).to_number();
176    let n = if n.is_finite() && n > 0.0 { n as usize } else { 0 };
177    let items = iterator_remaining(&this);
178    Ok(Value::Object(make_iterator(items.into_iter().take(n).collect())))
179}
180/// `Iterator.prototype.drop(n)`(ES2025)。
181pub fn iterator_drop(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
182    let n = arg(a, 0).to_number();
183    let n = if n.is_finite() && n > 0.0 { n as usize } else { 0 };
184    let items = iterator_remaining(&this);
185    Ok(Value::Object(make_iterator(items.into_iter().skip(n).collect())))
186}
187/// `Iterator.prototype.toArray()`(ES2025)。
188pub fn iterator_to_array(_it: &mut Interp, this: Value, _a: &[Value]) -> Result<Value, Value> {
189    Ok(Value::Object(Obj::array(iterator_remaining(&this))))
190}
191/// `Iterator.prototype.forEach(fn)`(ES2025)。
192pub fn iterator_for_each(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
193    let cb = arg(a, 0);
194    let items = iterator_remaining(&this);
195    for (i, v) in items.into_iter().enumerate() {
196        it.call_value(&cb, Value::Undefined, &[v, Value::Number(i as f64)])?;
197    }
198    Ok(Value::Undefined)
199}
200/// `Iterator.prototype.flatMap(fn)`(ES2025 Iterator Helpers。`map`/`filter`/`take`/
201/// `drop`/`toArray`/`forEach`/`reduce`/`some`/`every`/`find` は既に対応済みだったが、
202/// この提案の最後の1つが丸ごと未対応だった)。各要素にコールバックを適用し、
203/// その戻り値(イテラブルであることが前提)を1段だけ展開して連結する
204/// (`Array.prototype.flatMap` と同じ「1段だけ」の展開規則)。
205pub fn iterator_flat_map(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
206    let cb = arg(a, 0);
207    let items = iterator_remaining(&this);
208    let mut out = Vec::new();
209    for (i, v) in items.into_iter().enumerate() {
210        let mapped = it.call_value(&cb, Value::Undefined, &[v, Value::Number(i as f64)])?;
211        out.extend(it.iter_to_vec(&mapped));
212    }
213    Ok(Value::Object(make_iterator(out)))
214}
215/// `Iterator.prototype.some(fn)`/`.every(fn)`/`.find(fn)`(ES2025 Iterator Helpers。
216/// `map`/`filter`/`take`/`drop`/`toArray`/`forEach`/`reduce` は既に対応済みだったが、
217/// 同じ提案に含まれるこの3つが丸ごと未対応だった)。他のヘルパと同じ「残り要素を
218/// まとめて処理する即時評価」方式(無限イテレータには非対応の簡略実装)。
219pub fn iterator_some(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
220    let cb = arg(a, 0);
221    let items = iterator_remaining(&this);
222    for (i, v) in items.into_iter().enumerate() {
223        let r = it.call_value(&cb, Value::Undefined, &[v, Value::Number(i as f64)])?;
224        if r.truthy() {
225            return Ok(Value::Bool(true));
226        }
227    }
228    Ok(Value::Bool(false))
229}
230pub fn iterator_every(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
231    let cb = arg(a, 0);
232    let items = iterator_remaining(&this);
233    for (i, v) in items.into_iter().enumerate() {
234        let r = it.call_value(&cb, Value::Undefined, &[v, Value::Number(i as f64)])?;
235        if !r.truthy() {
236            return Ok(Value::Bool(false));
237        }
238    }
239    Ok(Value::Bool(true))
240}
241pub fn iterator_find(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
242    let cb = arg(a, 0);
243    let items = iterator_remaining(&this);
244    for (i, v) in items.into_iter().enumerate() {
245        let r = it.call_value(&cb, Value::Undefined, &[v.clone(), Value::Number(i as f64)])?;
246        if r.truthy() {
247            return Ok(v);
248        }
249    }
250    Ok(Value::Undefined)
251}
252/// `Iterator.prototype.reduce(fn, initial?)`(ES2025)。
253pub fn iterator_reduce(it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
254    let cb = arg(a, 0);
255    let items = iterator_remaining(&this);
256    let mut iter = items.into_iter().enumerate();
257    let mut acc = if a.len() > 1 {
258        arg(a, 1)
259    } else {
260        match iter.next() {
261            Some((_, v)) => v,
262            None => return Err(it.error("Reduce of empty iterator with no initial value")),
263        }
264    };
265    for (i, v) in iter {
266        acc = it.call_value(&cb, Value::Undefined, &[acc, v, Value::Number(i as f64)])?;
267    }
268    Ok(acc)
269}
270pub(crate) fn arr_entries(it: &mut Interp, t: Value, _a: &[Value]) -> Result<Value, Value> {
271    let out: Vec<Value> = generic_array_items(it, &t)
272        .into_iter()
273        .enumerate()
274        .map(|(i, v)| Value::Object(Obj::array(alloc::vec![Value::Number(i as f64), v])))
275        .collect();
276    Ok(Value::Object(make_iterator(out)))
277}
278pub(crate) fn arr_keys(it: &mut Interp, t: Value, _a: &[Value]) -> Result<Value, Value> {
279    let n = generic_array_items(it, &t).len();
280    Ok(Value::Object(make_iterator(
281        (0..n).map(|i| Value::Number(i as f64)).collect(),
282    )))
283}
284pub(crate) fn arr_values(it: &mut Interp, t: Value, _a: &[Value]) -> Result<Value, Value> {
285    let items = generic_array_items(it, &t);
286    Ok(Value::Object(make_iterator(items)))
287}
288pub(crate) fn arr_reduce_right(it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
289    let items = generic_array_items(it, &t);
290    let f = arg(a, 0);
291    let (mut acc, start) = if a.len() > 1 {
292        (arg(a, 1), items.len())
293    } else if items.is_empty() {
294        return Err(it.error("Reduce of empty array with no initial value"));
295    } else {
296        (items[items.len() - 1].clone(), items.len() - 1)
297    };
298    for i in (0..start).rev() {
299        acc = it.call_value(
300            &f,
301            Value::Undefined,
302            &[acc, items[i].clone(), Value::Number(i as f64), t.clone()],
303        )?;
304    }
305    Ok(acc)
306}
307
308// ===== 追加の String メソッド =====
309pub(crate) fn str_at(_it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
310    let chars: Vec<char> = this_str(&t).chars().collect();
311    let n = arg(a, 0).to_number() as i64;
312    let len = chars.len() as i64;
313    let idx = if n < 0 { len + n } else { n };
314    if idx >= 0 && idx < len {
315        Ok(Value::str(chars[idx as usize].to_string()))
316    } else {
317        Ok(Value::Undefined)
318    }
319}
320
321// ===== 追加の Promise 静的メソッド =====
322/// 値を「Promise 化した状態」に正規化する共通ヘルパ。本物の Promise ならその
323/// state、汎用 thenable(`.then` を持つがそれ自体は Promise ではないオブジェクト。
324/// `Promise.resolve`/`await` は同化に対応済みだったが `allSettled`/`race`/`any` の
325/// 配列要素だけ「非 Promise」として素通ししてしまう非対称なバグがあった)なら
326/// 新規 pending state を作って `promise_resolve`(thenable 同化に対応済み)に通す。
327/// どちらでもなければ `None`(呼び出し側は元の値をそのまま扱う)。
328pub(crate) fn resolve_maybe_thenable(
329    it: &mut Interp,
330    item: &Value,
331) -> Option<PromiseRc<PromiseRefCell<PromiseState>>> {
332    if let Some(s) = this_promise_state(item) {
333        return Some(s);
334    }
335    // own プロパティだけを見ると `class MyThenable { then(resolve){...} }` の
336    // ようにメソッドが `.prototype` 側にあるクラスインスタンスを取りこぼすため
337    // (`promise_resolve` 側の同種バグと合わせて自己検証で発見)、プロトタイプ
338    // 連鎖を辿る `get_property` を使う。
339    let then_fn = if matches!(item, Value::Object(_)) {
340        it.get_property(item, "then").unwrap_or(Value::Undefined)
341    } else {
342        Value::Undefined
343    };
344    let has_then = matches!(&then_fn, Value::Object(f) if f.borrow().is_callable());
345    if has_then {
346        let s = new_pending();
347        it.promise_resolve(&s, item.clone());
348        Some(s)
349    } else {
350        None
351    }
352}
353pub(crate) fn promise_all_settled_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
354    let items = it.iter_to_vec(&arg(a, 0));
355    let result = new_pending();
356    it.run_microtasks();
357    let mut out: Vec<Value> = Vec::new();
358    for item in items {
359        let o = Obj::plain();
360        {
361            let mut b = o.borrow_mut();
362            match resolve_maybe_thenable(it, &item) {
363                Some(s) => {
364                    let st = s.borrow();
365                    match st.status {
366                        PromiseStatus::Rejected => {
367                            b.props.insert("status".into(), Value::str("rejected"));
368                            b.props.insert("reason".into(), st.value.clone());
369                        }
370                        _ => {
371                            b.props.insert("status".into(), Value::str("fulfilled"));
372                            b.props.insert("value".into(), st.value.clone());
373                        }
374                    }
375                }
376                None => {
377                    b.props.insert("status".into(), Value::str("fulfilled"));
378                    b.props.insert("value".into(), item.clone());
379                }
380            }
381        }
382        out.push(Value::Object(o));
383    }
384    it.promise_resolve(&result, Value::Object(Obj::array(out)));
385    Ok(Value::Object(Obj::promise(result)))
386}
387pub(crate) fn promise_race_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
388    let items = it.iter_to_vec(&arg(a, 0));
389    let result = new_pending();
390    it.run_microtasks();
391    for item in items {
392        match resolve_maybe_thenable(it, &item) {
393            Some(s) => {
394                let (status, val) = {
395                    let b = s.borrow();
396                    (b.status, b.value.clone())
397                };
398                match status {
399                    PromiseStatus::Fulfilled => {
400                        it.promise_resolve(&result, val);
401                        return Ok(Value::Object(Obj::promise(result)));
402                    }
403                    PromiseStatus::Rejected => {
404                        it.promise_reject(&result, val);
405                        return Ok(Value::Object(Obj::promise(result)));
406                    }
407                    PromiseStatus::Pending => {}
408                }
409            }
410            None => {
411                it.promise_resolve(&result, item.clone());
412                return Ok(Value::Object(Obj::promise(result)));
413            }
414        }
415    }
416    Ok(Value::Object(Obj::promise(result)))
417}
418/// `Promise.any(iterable)`(ES2021)。以前は全て reject した場合に最後の reject 理由
419/// だけをそのまま投げており、仕様上必要な `AggregateError`(`.errors` に全 reject 理由を
420/// 保持する専用の例外型。`AggregateError` 自体が丸ごと欠落していた)を一切使っていなかった。
421/// 途中の理由が失われる(1つ目が reject でも最後だけ見える)バグも合わせて修正。
422pub(crate) fn promise_any_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
423    let items = it.iter_to_vec(&arg(a, 0));
424    let result = new_pending();
425    it.run_microtasks();
426    let mut reasons: Vec<Value> = Vec::new();
427    for item in items {
428        match resolve_maybe_thenable(it, &item) {
429            Some(s) => {
430                let (status, val) = {
431                    let b = s.borrow();
432                    (b.status, b.value.clone())
433                };
434                match status {
435                    PromiseStatus::Fulfilled => {
436                        it.promise_resolve(&result, val);
437                        return Ok(Value::Object(Obj::promise(result)));
438                    }
439                    PromiseStatus::Rejected => {
440                        reasons.push(val);
441                    }
442                    PromiseStatus::Pending => {}
443                }
444            }
445            None => {
446                it.promise_resolve(&result, item.clone());
447                return Ok(Value::Object(Obj::promise(result)));
448            }
449        }
450    }
451    let agg = make_aggregate_error(it, reasons, "All promises were rejected");
452    it.promise_reject(&result, agg);
453    Ok(Value::Object(Obj::promise(result)))
454}
455
456/// `Iterator.concat(...iterables)`(ES2025 Standard)。
457/// 複数のイテラブルオブジェクトの要素を順番に連結した新しい Iterator を返す。
458pub fn iterator_concat_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
459    let mut combined = Vec::new();
460    for arg_val in a {
461        let items = it.iter_to_vec(arg_val);
462        combined.extend(items);
463    }
464    Ok(Value::Object(make_iterator(combined)))
465}
466
467/// `Iterator.from(iterable)`(ES2025 Standard)。
468/// 指定されたイテラブルオブジェクトから Iterator オブジェクトを返す。
469pub fn iterator_from_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
470    let source = arg(a, 0);
471    let items = it.iter_to_vec(&source);
472    Ok(Value::Object(make_iterator(items)))
473}