boa/syntax/ast/node/object/
mod.rs1use crate::{
4 exec::Executable,
5 gc::{Finalize, Trace},
6 property::PropertyDescriptor,
7 syntax::ast::node::{join_nodes, MethodDefinitionKind, Node, PropertyDefinition, PropertyName},
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#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
38#[cfg_attr(feature = "deser", serde(transparent))]
39#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
40pub struct Object {
41 properties: Box<[PropertyDefinition]>,
42}
43
44impl Object {
45 pub fn properties(&self) -> &[PropertyDefinition] {
46 &self.properties
47 }
48
49 pub(in crate::syntax::ast::node) fn display(
51 &self,
52 f: &mut fmt::Formatter<'_>,
53 indent: usize,
54 ) -> fmt::Result {
55 f.write_str("{\n")?;
56 let indentation = " ".repeat(indent + 1);
57 for property in self.properties().iter() {
58 match property {
59 PropertyDefinition::IdentifierReference(key) => {
60 writeln!(f, "{}{},", indentation, key)?;
61 }
62 PropertyDefinition::Property(key, value) => {
63 write!(f, "{}{}: ", indentation, key,)?;
64 value.display_no_indent(f, indent + 1)?;
65 writeln!(f, ",")?;
66 }
67 PropertyDefinition::SpreadObject(key) => {
68 writeln!(f, "{}...{},", indentation, key)?;
69 }
70 PropertyDefinition::MethodDefinition(kind, key, node) => {
71 write!(f, "{}", indentation)?;
72 match &kind {
73 MethodDefinitionKind::Get => write!(f, "get ")?,
74 MethodDefinitionKind::Set => write!(f, "set ")?,
75 MethodDefinitionKind::Ordinary => (),
76 }
77 write!(f, "{}(", key)?;
78 join_nodes(f, node.parameters())?;
79 write!(f, ") ")?;
80 node.display_block(f, indent + 1)?;
81 writeln!(f, ",")?;
82 }
83 }
84 }
85 write!(f, "{}}}", " ".repeat(indent))
86 }
87}
88
89impl Executable for Object {
90 fn run(&self, context: &mut Context) -> JsResult<JsValue> {
91 let _timer = BoaProfiler::global().start_event("object", "exec");
92 let obj = JsValue::new_object(context);
93
94 for property in self.properties().iter() {
96 match property {
97 PropertyDefinition::Property(name, value) => {
98 let name = match name {
99 PropertyName::Literal(name) => name.clone().into(),
100 PropertyName::Computed(node) => {
101 node.run(context)?.to_property_key(context)?
102 }
103 };
104 obj.set_property(
105 name,
106 PropertyDescriptor::builder()
107 .value(value.run(context)?)
108 .writable(true)
109 .enumerable(true)
110 .configurable(true),
111 );
112 }
113 PropertyDefinition::MethodDefinition(kind, name, func) => {
114 let name = match name {
115 PropertyName::Literal(name) => name.clone().into(),
116 PropertyName::Computed(node) => {
117 node.run(context)?.to_property_key(context)?
118 }
119 };
120 match kind {
121 MethodDefinitionKind::Ordinary => {
122 obj.set_property(
123 name,
124 PropertyDescriptor::builder()
125 .value(func.run(context)?)
126 .writable(true)
127 .enumerable(true)
128 .configurable(true),
129 );
130 }
131 MethodDefinitionKind::Get => {
132 let set = obj
133 .get_property(name.clone())
134 .as_ref()
135 .and_then(|a| a.set())
136 .cloned();
137 obj.set_property(
138 name,
139 PropertyDescriptor::builder()
140 .maybe_get(func.run(context)?.as_object())
141 .maybe_set(set)
142 .enumerable(true)
143 .configurable(true),
144 )
145 }
146 MethodDefinitionKind::Set => {
147 let get = obj
148 .get_property(name.clone())
149 .as_ref()
150 .and_then(|a| a.get())
151 .cloned();
152 obj.set_property(
153 name,
154 PropertyDescriptor::builder()
155 .maybe_get(get)
156 .maybe_set(func.run(context)?.as_object())
157 .enumerable(true)
158 .configurable(true),
159 )
160 }
161 }
162 }
163 PropertyDefinition::SpreadObject(node) => {
165 let val = node.run(context)?;
166
167 if val.is_null_or_undefined() {
168 continue;
169 }
170
171 obj.as_object().unwrap().copy_data_properties::<String>(
172 &val,
173 vec![],
174 context,
175 )?;
176 }
177 _ => {} }
179 }
180
181 Ok(obj)
182 }
183}
184
185impl fmt::Display for Object {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 self.display(f, 0)
188 }
189}
190
191impl<T> From<T> for Object
192where
193 T: Into<Box<[PropertyDefinition]>>,
194{
195 fn from(props: T) -> Self {
196 Self {
197 properties: props.into(),
198 }
199 }
200}
201
202impl From<Object> for Node {
203 fn from(obj: Object) -> Self {
204 Self::Object(obj)
205 }
206}