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