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    let holes = super::props_methods::holes_of(&t);
299    for i in (0..start).rev() {
300        if holes.get(i).copied().unwrap_or(false) {
301            continue;
302        }
303        acc = it.call_value(
304            &f,
305            Value::Undefined,
306            &[acc, items[i].clone(), Value::Number(i as f64), t.clone()],
307        )?;
308    }
309    Ok(acc)
310}
311
312// ===== 追加の String メソッド =====
313pub(crate) fn str_at(_it: &mut Interp, t: Value, a: &[Value]) -> Result<Value, Value> {
314    let chars: Vec<char> = this_str(&t).chars().collect();
315    let n = arg(a, 0).to_number() as i64;
316    let len = chars.len() as i64;
317    let idx = if n < 0 { len + n } else { n };
318    if idx >= 0 && idx < len {
319        Ok(Value::str(chars[idx as usize].to_string()))
320    } else {
321        Ok(Value::Undefined)
322    }
323}
324
325// ===== 追加の Promise 静的メソッド =====
326/// 値を「Promise 化した状態」に正規化する共通ヘルパ。本物の Promise ならその
327/// state、汎用 thenable(`.then` を持つがそれ自体は Promise ではないオブジェクト。
328/// `Promise.resolve`/`await` は同化に対応済みだったが `allSettled`/`race`/`any` の
329/// 配列要素だけ「非 Promise」として素通ししてしまう非対称なバグがあった)なら
330/// 新規 pending state を作って `promise_resolve`(thenable 同化に対応済み)に通す。
331/// どちらでもなければ `None`(呼び出し側は元の値をそのまま扱う)。
332pub(crate) fn resolve_maybe_thenable(
333    it: &mut Interp,
334    item: &Value,
335) -> Option<PromiseRc<PromiseRefCell<PromiseState>>> {
336    if let Some(s) = this_promise_state(item) {
337        return Some(s);
338    }
339    // own プロパティだけを見ると `class MyThenable { then(resolve){...} }` の
340    // ようにメソッドが `.prototype` 側にあるクラスインスタンスを取りこぼすため
341    // (`promise_resolve` 側の同種バグと合わせて自己検証で発見)、プロトタイプ
342    // 連鎖を辿る `get_property` を使う。
343    let then_fn = if matches!(item, Value::Object(_)) {
344        it.get_property(item, "then").unwrap_or(Value::Undefined)
345    } else {
346        Value::Undefined
347    };
348    let has_then = matches!(&then_fn, Value::Object(f) if f.borrow().is_callable());
349    if has_then {
350        let s = new_pending();
351        it.promise_resolve(&s, item.clone());
352        Some(s)
353    } else {
354        None
355    }
356}
357pub(crate) fn promise_all_settled_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
358    let items = it.iter_to_vec(&arg(a, 0));
359    let result = new_pending();
360    it.run_microtasks();
361    let mut out: Vec<Value> = Vec::new();
362    for item in items {
363        let o = Obj::plain();
364        {
365            let mut b = o.borrow_mut();
366            match resolve_maybe_thenable(it, &item) {
367                Some(s) => {
368                    let st = s.borrow();
369                    match st.status {
370                        PromiseStatus::Rejected => {
371                            b.props.insert("status".into(), Value::str("rejected"));
372                            b.props.insert("reason".into(), st.value.clone());
373                        }
374                        _ => {
375                            b.props.insert("status".into(), Value::str("fulfilled"));
376                            b.props.insert("value".into(), st.value.clone());
377                        }
378                    }
379                }
380                None => {
381                    b.props.insert("status".into(), Value::str("fulfilled"));
382                    b.props.insert("value".into(), item.clone());
383                }
384            }
385        }
386        out.push(Value::Object(o));
387    }
388    it.promise_resolve(&result, Value::Object(Obj::array(out)));
389    Ok(Value::Object(Obj::promise(result)))
390}
391pub(crate) fn promise_race_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
392    let items = it.iter_to_vec(&arg(a, 0));
393    let result = new_pending();
394    it.run_microtasks();
395    for item in items {
396        match resolve_maybe_thenable(it, &item) {
397            Some(s) => {
398                let (status, val) = {
399                    let b = s.borrow();
400                    (b.status, b.value.clone())
401                };
402                match status {
403                    PromiseStatus::Fulfilled => {
404                        it.promise_resolve(&result, val);
405                        return Ok(Value::Object(Obj::promise(result)));
406                    }
407                    PromiseStatus::Rejected => {
408                        it.promise_reject(&result, val);
409                        return Ok(Value::Object(Obj::promise(result)));
410                    }
411                    PromiseStatus::Pending => {}
412                }
413            }
414            None => {
415                it.promise_resolve(&result, item.clone());
416                return Ok(Value::Object(Obj::promise(result)));
417            }
418        }
419    }
420    Ok(Value::Object(Obj::promise(result)))
421}
422/// `Promise.any(iterable)`(ES2021)。以前は全て reject した場合に最後の reject 理由
423/// だけをそのまま投げており、仕様上必要な `AggregateError`(`.errors` に全 reject 理由を
424/// 保持する専用の例外型。`AggregateError` 自体が丸ごと欠落していた)を一切使っていなかった。
425/// 途中の理由が失われる(1つ目が reject でも最後だけ見える)バグも合わせて修正。
426pub(crate) fn promise_any_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
427    let items = it.iter_to_vec(&arg(a, 0));
428    let result = new_pending();
429    it.run_microtasks();
430    let mut reasons: Vec<Value> = Vec::new();
431    for item in items {
432        match resolve_maybe_thenable(it, &item) {
433            Some(s) => {
434                let (status, val) = {
435                    let b = s.borrow();
436                    (b.status, b.value.clone())
437                };
438                match status {
439                    PromiseStatus::Fulfilled => {
440                        it.promise_resolve(&result, val);
441                        return Ok(Value::Object(Obj::promise(result)));
442                    }
443                    PromiseStatus::Rejected => {
444                        reasons.push(val);
445                    }
446                    PromiseStatus::Pending => {}
447                }
448            }
449            None => {
450                it.promise_resolve(&result, item.clone());
451                return Ok(Value::Object(Obj::promise(result)));
452            }
453        }
454    }
455    let agg = make_aggregate_error(it, reasons, "All promises were rejected");
456    it.promise_reject(&result, agg);
457    Ok(Value::Object(Obj::promise(result)))
458}
459
460/// `Iterator.concat(...iterables)`(ES2025 Standard)。
461/// 複数のイテラブルオブジェクトの要素を順番に連結した新しい Iterator を返す。
462pub fn iterator_concat_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
463    let mut combined = Vec::new();
464    for arg_val in a {
465        let items = it.iter_to_vec(arg_val);
466        combined.extend(items);
467    }
468    Ok(Value::Object(make_iterator(combined)))
469}
470
471/// `Iterator.from(iterable)`(ES2025 Standard)。
472/// 指定されたイテラブルオブジェクトから Iterator オブジェクトを返す。
473pub fn iterator_from_static(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
474    let source = arg(a, 0);
475    let items = it.iter_to_vec(&source);
476    Ok(Value::Object(make_iterator(items)))
477}