boa/syntax/ast/node/array/
mod.rs

1//! Array declaration node.
2
3use super::{join_nodes, Node};
4use crate::{
5    builtins::{iterable, Array},
6    exec::Executable,
7    gc::{Finalize, Trace},
8    BoaProfiler, Context, JsResult, JsValue,
9};
10use std::fmt;
11
12#[cfg(feature = "deser")]
13use serde::{Deserialize, Serialize};
14
15#[cfg(test)]
16mod tests;
17
18/// An array is an ordered collection of data (either primitive or object depending upon the
19/// language).
20///
21/// Arrays are used to store multiple values in a single variable.
22/// This is compared to a variable that can store only one value.
23///
24/// Each item in an array has a number attached to it, called a numeric index, that allows you
25/// to access it. In JavaScript, arrays start at index zero and can be manipulated with various
26/// methods.
27///
28/// More information:
29///  - [ECMAScript reference][spec]
30///  - [MDN documentation][mdn]
31///
32/// [spec]: https://tc39.es/ecma262/#prod-ArrayLiteral
33/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
34#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
35#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
36pub struct ArrayDecl {
37    #[cfg_attr(feature = "deser", serde(flatten))]
38    arr: Box<[Node]>,
39}
40
41impl Executable for ArrayDecl {
42    fn run(&self, context: &mut Context) -> JsResult<JsValue> {
43        let _timer = BoaProfiler::global().start_event("ArrayDecl", "exec");
44        let array = Array::new_array(context);
45        let mut elements = Vec::new();
46        for elem in self.as_ref() {
47            if let Node::Spread(ref x) = elem {
48                let val = x.run(context)?;
49                let iterator_record = iterable::get_iterator(&val, context)?;
50                // TODO after proper internal Array representation as per https://github.com/boa-dev/boa/pull/811#discussion_r502460858
51                // next_index variable should be utilized here as per https://tc39.es/ecma262/#sec-runtime-semantics-arrayaccumulation
52                // let mut next_index = 0;
53                loop {
54                    let next = iterator_record.next(context)?;
55                    if next.done {
56                        break;
57                    }
58                    let next_value = next.value;
59                    //next_index += 1;
60                    elements.push(next_value);
61                }
62            } else {
63                elements.push(elem.run(context)?);
64            }
65        }
66
67        Array::add_to_array_object(&array, &elements, context)?;
68        Ok(array)
69    }
70}
71
72impl AsRef<[Node]> for ArrayDecl {
73    fn as_ref(&self) -> &[Node] {
74        &self.arr
75    }
76}
77
78impl<T> From<T> for ArrayDecl
79where
80    T: Into<Box<[Node]>>,
81{
82    fn from(decl: T) -> Self {
83        Self { arr: decl.into() }
84    }
85}
86
87impl fmt::Display for ArrayDecl {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.write_str("[")?;
90        join_nodes(f, &self.arr)?;
91        f.write_str("]")
92    }
93}
94
95impl From<ArrayDecl> for Node {
96    fn from(arr: ArrayDecl) -> Self {
97        Self::ArrayDecl(arr)
98    }
99}