1use crate::runner::ds::error::JErrorType;
2use crate::runner::ds::execution_context::ExecutionContextStack;
3use crate::runner::ds::function_object::JsFunctionObject;
4use crate::runner::ds::iterator_object::JsIteratorObject;
5use crate::runner::ds::object_property::{
6 PropertyDescriptor, PropertyDescriptorAccessor, PropertyDescriptorData,
7 PropertyDescriptorSetter, PropertyKey,
8};
9use crate::runner::ds::operations::object::{get, get_function_realm};
10use crate::runner::ds::operations::test_and_comparison::{
11 is_constructor, same_js_object, same_object, same_value,
12};
13use crate::runner::ds::operations::type_conversion::{
14 canonical_numeric_index_string, to_string_int,
15};
16use crate::runner::ds::realm::WellKnownIntrinsics;
17use crate::runner::ds::value::{JsValue, JsValueOrSelf};
18use std::cell::RefCell;
19use std::collections::HashMap;
20use std::fmt;
21use std::fmt::{Display, Formatter};
22use std::ops::Deref;
23use std::rc::Rc;
24
25lazy_static! {
26 pub static ref OBJECT_PROTOTYPE_PROP: PropertyKey = PropertyKey::Str("prototype".to_string());
27}
28
29pub type JsObjectType = Rc<RefCell<ObjectType>>;
30
31pub enum ObjectType {
32 Ordinary(Box<dyn JsObject>),
33 Function(Box<dyn JsFunctionObject>),
34}
35impl ObjectType {
36 pub fn is_callable(&self) -> bool {
37 match self {
38 ObjectType::Function(_) => true,
39 ObjectType::Ordinary(obj) => {
40 let marker = PropertyKey::Str("__simple_function__".to_string());
42 obj.get_object_base().properties.contains_key(&marker)
43 }
44 }
45 }
46
47 pub fn is_constructor(&self) -> bool {
48 is_constructor(self)
49 }
50
51 pub fn as_js_object(&self) -> &dyn JsObject {
52 match self {
53 ObjectType::Ordinary(o) => o.as_js_object(),
54 ObjectType::Function(o) => o.as_js_object(),
55 }
56 }
57
58 pub fn as_js_object_mut(&mut self) -> &mut dyn JsObject {
59 match self {
60 ObjectType::Ordinary(o) => o.as_js_object_mut(),
61 ObjectType::Function(o) => o.as_js_object_mut(),
62 }
63 }
64
65 pub fn as_js_function_object(&self) -> &dyn JsFunctionObject {
66 match self {
67 ObjectType::Ordinary(_o) => panic!("Not callable hence cannot get as JsFunctionObject"),
68 ObjectType::Function(o) => o.as_js_function_object(),
69 }
70 }
71
72 pub fn as_js_function_object_mut(&mut self) -> &mut dyn JsFunctionObject {
73 match self {
74 ObjectType::Ordinary(_o) => panic!("Not callable hence cannot get as JsFunctionObject"),
75 ObjectType::Function(o) => o.as_js_function_object_mut(),
76 }
77 }
78}
79impl PartialEq for ObjectType {
80 fn eq(&self, other: &Self) -> bool {
81 match self {
82 ObjectType::Ordinary(o) => {
83 if let ObjectType::Ordinary(o1) = other {
84 same_js_object(o.deref(), o1.deref())
85 } else {
86 false
87 }
88 }
89 ObjectType::Function(o) => {
90 if let ObjectType::Function(o1) = other {
91 same_js_object(o.deref().as_js_object(), o1.deref().as_js_object())
92 } else {
93 false
94 }
95 }
96 }
97 }
98}
99impl Display for ObjectType {
100 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
101 write!(f, "{}", self.as_js_object().to_string())
102 }
103}
104
105pub struct ObjectBase {
106 pub properties: HashMap<PropertyKey, PropertyDescriptor>,
107 pub is_extensible: bool,
108 pub prototype: Option<JsObjectType>,
109}
110impl ObjectBase {
111 pub fn new() -> Self {
112 ObjectBase {
113 properties: HashMap::new(),
114 is_extensible: true,
115 prototype: None,
116 }
117 }
118}
119
120pub trait JsObject {
121 fn get_object_base_mut(&mut self) -> &mut ObjectBase;
122
123 fn get_object_base(&self) -> &ObjectBase;
124
125 fn as_js_object(&self) -> &dyn JsObject;
126
127 fn as_js_object_mut(&mut self) -> &mut dyn JsObject;
128
129 fn get_prototype_of(&self) -> Option<JsObjectType> {
130 match &self.get_object_base().prototype {
131 None => None,
132 Some(j) => Some(j.clone()),
133 }
134 }
135
136 fn set_prototype_of(&mut self, prototype: Option<JsObjectType>) -> bool {
137 let current_value = &self.get_object_base().prototype;
138 let new_value: Option<JsObjectType> = match prototype {
139 None => {
140 if current_value.is_none() {
141 return true;
142 } else {
143 None
144 }
145 }
146 Some(p) => {
147 if let Some(current_p) = current_value {
148 if same_object(
149 p.deref().borrow().deref(),
150 current_p.deref().borrow().deref(),
151 ) {
152 return true;
153 } else {
154 Some(p.clone())
155 }
156 } else {
157 None
158 }
159 }
160 };
161 if self.is_extensible() {
162 if let Some(new_value) = new_value {
163 let mut p = Some(new_value.clone());
164 loop {
165 if let Some(some_p) = p {
166 if same_js_object(self.as_js_object(), (*(*some_p).borrow()).as_js_object())
167 {
168 return false;
170 } else {
171 let t1 = (*some_p).borrow();
172 let t2 = (*t1).as_js_object().get_prototype_of();
173 p = t2;
174 }
175 } else {
176 break;
177 }
178 }
179 self.get_object_base_mut().prototype = Some(new_value);
180 } else {
181 self.get_object_base_mut().prototype = None;
182 }
183 true
184 } else {
185 false
186 }
187 }
188
189 fn is_extensible(&self) -> bool {
190 self.get_object_base().is_extensible
191 }
192
193 fn prevent_extensions(&mut self) -> bool {
194 self.get_object_base_mut().is_extensible = false;
195 true
196 }
197
198 fn get_own_property(
199 &self,
200 property: &PropertyKey,
201 ) -> Result<Option<&PropertyDescriptor>, JErrorType> {
202 Ok(self.get_object_base().properties.get(property))
203 }
204
205 fn define_own_property(
206 &mut self,
207 property: PropertyKey,
208 descriptor_setter: PropertyDescriptorSetter,
209 ) -> Result<bool, JErrorType> {
210 ordinary_define_own_property(self, property, descriptor_setter)
211 }
212
213 fn has_property(&self, property: &PropertyKey) -> bool {
214 if self.get_object_base().properties.contains_key(property) {
215 true
216 } else {
217 match &self.get_object_base().prototype {
218 None => false,
219 Some(o) => (**o).borrow().as_js_object().has_property(property),
220 }
221 }
222 }
223
224 fn get(
225 &self,
226 ctx_stack: &mut ExecutionContextStack,
227 property: &PropertyKey,
228 receiver: JsValueOrSelf,
229 ) -> Result<JsValue, JErrorType> {
230 match self.get_own_property(property)? {
231 None => match self.get_prototype_of() {
232 None => Ok(JsValue::Undefined),
233 Some(p) => (*(*p).borrow())
234 .as_js_object()
235 .get(ctx_stack, property, receiver),
236 },
237 Some(pd) => match pd {
238 PropertyDescriptor::Data(PropertyDescriptorData { value, .. }) => Ok(value.clone()),
239 PropertyDescriptor::Accessor(PropertyDescriptorAccessor { get, .. }) => match get {
240 None => Ok(JsValue::Undefined),
241 Some(getter) => (**getter).borrow().as_js_function_object().call(
242 getter,
243 ctx_stack,
244 receiver,
245 Vec::new(),
246 ),
247 },
248 },
249 }
250 }
251
252 fn set(
253 &mut self,
254 ctx_stack: &mut ExecutionContextStack,
255 property: PropertyKey,
256 value: JsValue,
257 receiver: JsValueOrSelf,
258 ) -> Result<bool, JErrorType> {
259 let own_prop = self.get_own_property(&property)?;
261
262 match own_prop {
263 None => match self.get_prototype_of() {
264 None => {
265 self.get_object_base_mut().properties.insert(
266 property,
267 PropertyDescriptor::Data(PropertyDescriptorData {
268 value,
269 writable: true,
270 enumerable: true,
271 configurable: true,
272 }),
273 );
274 Ok(true)
275 }
276 Some(p) => (*p)
277 .borrow_mut()
278 .as_js_object_mut()
279 .set(ctx_stack, property, value, receiver),
280 },
281 Some(pd) => match pd {
282 PropertyDescriptor::Data(PropertyDescriptorData {
283 value: _, writable, ..
284 }) => {
285 if *writable {
286 match receiver {
287 JsValueOrSelf::ValueRef(value_ref) => match value_ref {
288 JsValue::Object(o) => {
289 let mut ot_obj = (**o).borrow_mut();
290 let obj = (*ot_obj).as_js_object_mut();
291 set_or_update_data_descriptor(obj, property, &value)
292 }
293 _ => Ok(false),
294 },
295 JsValueOrSelf::SelfValue => {
296 set_or_update_data_descriptor(self.as_js_object_mut(), property, &value)
297 }
298 }
299 } else {
300 Ok(false)
301 }
302 }
303 PropertyDescriptor::Accessor(PropertyDescriptorAccessor { set, .. }) => match set {
304 None => Ok(false),
305 Some(setter) => {
306 (**setter).borrow_mut().as_js_function_object_mut().call(
307 setter,
308 ctx_stack,
309 receiver,
310 vec![value],
311 )?;
312 Ok(true)
313 }
314 },
315 },
316 }
317 }
318
319 fn delete(&mut self, property: &PropertyKey) -> Result<bool, JErrorType> {
320 Ok(match self.get_own_property(property)? {
321 None => true,
322 Some(pd) => {
323 if pd.is_configurable() {
324 self.get_object_base_mut().properties.remove(property);
325 true
326 } else {
327 false
328 }
329 }
330 })
331 }
332
333 fn enumerate(&self) -> JsIteratorObject {
334 todo!()
335 }
336
337 fn own_property_keys(&self, ctx_stack: &mut ExecutionContextStack) -> Vec<PropertyKey> {
338 let mut int_keys = vec![];
339 let mut str_keys = vec![];
340 let mut sym_keys = vec![];
341 for (key, _) in &self.get_object_base().properties {
342 match key {
343 PropertyKey::Str(d) => {
344 if let Some(idx) = canonical_numeric_index_string(ctx_stack, d) {
345 int_keys.push(idx);
346 } else {
347 str_keys.push(d.to_string());
348 }
349 }
350 PropertyKey::Sym(d) => {
351 sym_keys.push(d.clone());
352 }
353 }
354 }
355 int_keys.sort();
356
357 let mut result = vec![];
358 result.append(
359 &mut int_keys
360 .into_iter()
361 .map(|v| PropertyKey::Str(to_string_int(v as i64)))
362 .collect::<Vec<PropertyKey>>(),
363 );
364 result.append(
365 &mut str_keys
366 .into_iter()
367 .map(|v| PropertyKey::Str(v))
368 .collect::<Vec<PropertyKey>>(),
369 );
370 result.append(
371 &mut sym_keys
372 .into_iter()
373 .map(|v| PropertyKey::Sym(v))
374 .collect::<Vec<PropertyKey>>(),
375 );
376 result
377 }
378
379 fn to_string(&self) -> String {
380 format!("object")
381 }
382}
383
384pub struct CoreObject {
385 base: ObjectBase,
386}
387impl CoreObject {
388 fn new(proto: Option<JsObjectType>) -> Self {
389 let mut o = CoreObject {
390 base: ObjectBase::new(),
391 };
392 finish_object_create(&mut o, proto);
393 o
394 }
395
396 fn new_from_constructor(
397 ctx_stack: &mut ExecutionContextStack,
398 constructor: JsObjectType,
399 intrinsic_default_proto: &WellKnownIntrinsics,
400 ) -> Result<Self, JErrorType> {
401 let mut o = CoreObject {
402 base: ObjectBase::new(),
403 };
404 finish_object_create_from_constructor(
405 ctx_stack,
406 &mut o,
407 constructor,
408 intrinsic_default_proto,
409 )?;
410 Ok(o)
411 }
412}
413impl JsObject for CoreObject {
414 fn get_object_base_mut(&mut self) -> &mut ObjectBase {
415 &mut self.base
416 }
417
418 fn get_object_base(&self) -> &ObjectBase {
419 &self.base
420 }
421
422 fn as_js_object(&self) -> &dyn JsObject {
423 self
424 }
425
426 fn as_js_object_mut(&mut self) -> &mut dyn JsObject {
427 self
428 }
429}
430
431pub fn ordinary_define_own_property<J: JsObject + ?Sized>(
432 o: &mut J,
433 property: PropertyKey,
434 mut descriptor_setter: PropertyDescriptorSetter,
435) -> Result<bool, JErrorType> {
436 let current_descriptor = o.get_own_property(&property)?;
437 Ok(if let Some(current_descriptor) = current_descriptor {
438 if descriptor_setter.is_empty() {
439 true
440 } else if descriptor_setter.are_all_fields_set()
441 && current_descriptor == &descriptor_setter.descriptor
442 {
443 true
444 } else {
445 let descriptor = &descriptor_setter.descriptor;
446 if !current_descriptor.is_configurable() {
447 if descriptor.is_configurable() {
448 return Ok(false);
449 } else {
450 if (current_descriptor.is_enumerable() && !descriptor.is_enumerable())
451 || (!current_descriptor.is_enumerable() && descriptor.is_enumerable())
452 {
453 return Ok(false);
454 }
455 }
456 }
457 if !descriptor_setter.is_generic_descriptor() {
458 if (current_descriptor.is_data_descriptor() && !descriptor.is_data_descriptor())
459 || (!current_descriptor.is_data_descriptor() && descriptor.is_data_descriptor())
460 {
461 if !current_descriptor.is_configurable() {
462 return Ok(false);
463 }
464 descriptor_setter.descriptor = match descriptor_setter.descriptor {
465 PropertyDescriptor::Data(PropertyDescriptorData {
466 value,
467 writable,
468 ..
469 }) => PropertyDescriptor::Data(PropertyDescriptorData {
470 value,
471 writable,
472 enumerable: current_descriptor.is_enumerable(),
473 configurable: current_descriptor.is_configurable(),
474 }),
475 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
476 set: setter,
477 get: getter,
478 ..
479 }) => PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
480 set: setter,
481 get: getter,
482 enumerable: current_descriptor.is_enumerable(),
483 configurable: current_descriptor.is_configurable(),
484 }),
485 };
486 } else if current_descriptor.is_data_descriptor() && descriptor.is_data_descriptor()
487 {
488 if !current_descriptor.is_configurable() {
489 if let PropertyDescriptor::Data(PropertyDescriptorData {
490 writable: current_writable,
491 value: current_value,
492 ..
493 }) = current_descriptor
494 {
495 if let PropertyDescriptor::Data(PropertyDescriptorData {
496 writable: desc_writable,
497 value: desc_value,
498 ..
499 }) = &descriptor
500 {
501 if !*current_writable && *desc_writable {
502 return Ok(false);
503 }
504 if !*current_writable {
505 if descriptor_setter.honour_value
506 && !same_value(current_value, desc_value)
507 {
508 return Ok(false);
509 }
510 }
511 }
512 }
513 }
514 } else if current_descriptor.is_accessor_descriptor()
515 && descriptor.is_accessor_descriptor()
516 {
517 if !current_descriptor.is_configurable() {
518 if let PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
519 set: current_set,
520 get: current_get,
521 ..
522 }) = current_descriptor
523 {
524 if let PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
525 set: desc_set,
526 get: desc_get,
527 ..
528 }) = &descriptor
529 {
530 if !(current_set.is_none() && desc_set.is_none())
531 && descriptor_setter.honour_set
532 && ((!current_set.is_none() && desc_set.is_none())
533 || (current_set.is_none() && !desc_set.is_none())
534 || !same_js_object(
535 current_set.as_ref().unwrap().borrow().as_js_object(),
536 desc_set.as_ref().unwrap().borrow().as_js_object(),
537 ))
538 {
539 return Ok(false);
540 }
541
542 if !(current_get.is_none() && desc_get.is_none())
543 && descriptor_setter.honour_get
544 && ((!current_get.is_none() && desc_get.is_none())
545 || (current_get.is_none() && !desc_get.is_none())
546 || !same_object(
547 &(*current_get.as_ref().unwrap()).borrow(),
548 &(*desc_get.as_ref().unwrap()).borrow(),
549 ))
550 {
551 return Ok(false);
552 }
553 }
554 }
555 }
556 }
557 }
558 o.get_object_base_mut().properties.insert(
559 property,
560 PropertyDescriptor::new_from_property_descriptor_setter(descriptor_setter),
561 );
562 true
563 }
564 } else {
565 if o.is_extensible() {
566 o.get_object_base_mut().properties.insert(
567 property,
568 PropertyDescriptor::new_from_property_descriptor_setter(descriptor_setter),
569 );
570 true
571 } else {
572 false
573 }
574 })
575}
576
577fn set_or_update_data_descriptor(
578 obj: &mut dyn JsObject,
579 property: PropertyKey,
580 value: &JsValue,
581) -> Result<bool, JErrorType> {
582 match obj.get_own_property(&property)? {
583 None => {
584 let desc_setter = PropertyDescriptorSetter::new_from_property_descriptor(
585 PropertyDescriptor::Data(PropertyDescriptorData {
586 value: value.clone(),
587 writable: true,
588 enumerable: true,
589 configurable: true,
590 }),
591 );
592 obj.define_own_property(property, desc_setter)?;
593 Ok(true)
594 }
595 Some(pd) => match pd {
596 PropertyDescriptor::Data(PropertyDescriptorData { writable, .. }) => {
597 if *writable {
598 obj.define_own_property(
599 property,
600 PropertyDescriptorSetter {
601 honour_value: true,
602 honour_writable: false,
603 honour_set: false,
604 honour_get: false,
605 honour_enumerable: false,
606 honour_configurable: false,
607 descriptor: PropertyDescriptor::Data(PropertyDescriptorData {
608 value: value.clone(),
609 writable: false,
610 enumerable: false,
611 configurable: false,
612 }),
613 },
614 )
615 } else {
616 Ok(false)
617 }
618 }
619 PropertyDescriptor::Accessor { .. } => Ok(false),
620 },
621 }
622}
623
624pub fn object_create(proto: Option<JsObjectType>) -> impl JsObject {
625 CoreObject::new(proto)
626}
627
628pub fn object_create_from_constructor(
629 ctx_stack: &mut ExecutionContextStack,
630 constructor: JsObjectType,
631 intrinsic_default_proto: &WellKnownIntrinsics,
632) -> Result<impl JsObject, JErrorType> {
633 CoreObject::new_from_constructor(ctx_stack, constructor, intrinsic_default_proto)
634}
635
636pub fn finish_object_create(obj: &mut dyn JsObject, proto: Option<JsObjectType>) {
637 obj.get_object_base_mut().prototype = proto;
638 obj.get_object_base_mut().is_extensible = true;
639}
640
641pub fn finish_object_create_from_constructor(
642 ctx_stack: &mut ExecutionContextStack,
643 obj: &mut dyn JsObject,
644 constructor: JsObjectType,
645 intrinsic_default_proto: &WellKnownIntrinsics,
646) -> Result<(), JErrorType> {
647 let proto = get_prototype_from_constructor(ctx_stack, constructor, intrinsic_default_proto)?;
648 finish_object_create(obj, Some(proto));
649 Ok(())
650}
651
652pub fn get_prototype_from_constructor(
653 ctx_stack: &mut ExecutionContextStack,
654 constructor: JsObjectType,
655 intrinsic_default_proto: &WellKnownIntrinsics,
656) -> Result<JsObjectType, JErrorType> {
657 let proto = get(ctx_stack, &constructor, &*OBJECT_PROTOTYPE_PROP)?;
658 if let JsValue::Object(o) = proto {
659 Ok(o)
660 } else {
661 let realm = get_function_realm(&*(*constructor).borrow())?;
662 let proto = (*realm)
663 .borrow()
664 .get_intrinsics_value(intrinsic_default_proto)
665 .clone();
666 Ok(proto)
667 }
668}