1use crate::{
4 builtins::{
5 self,
6 function::{Function, FunctionFlags, NativeFunction},
7 iterable::IteratorPrototypes,
8 },
9 class::{Class, ClassBuilder},
10 exec::Interpreter,
11 object::{FunctionBuilder, JsObject, Object, PROTOTYPE},
12 property::{Attribute, PropertyDescriptor, PropertyKey},
13 realm::Realm,
14 syntax::{
15 ast::{
16 node::{
17 statement_list::RcStatementList, Call, FormalParameter, Identifier, New,
18 StatementList,
19 },
20 Const, Node,
21 },
22 Parser,
23 },
24 BoaProfiler, Executable, JsResult, JsString, JsValue,
25};
26
27#[cfg(feature = "console")]
28use crate::builtins::console::Console;
29
30#[cfg(feature = "vm")]
31use crate::vm::Vm;
32
33#[derive(Debug, Clone)]
35pub struct StandardConstructor {
36 pub(crate) constructor: JsObject,
37 pub(crate) prototype: JsObject,
38}
39
40impl Default for StandardConstructor {
41 fn default() -> Self {
42 Self {
43 constructor: JsObject::new(Object::default()),
44 prototype: JsObject::new(Object::default()),
45 }
46 }
47}
48
49impl StandardConstructor {
50 fn with_prototype(prototype: Object) -> Self {
52 Self {
53 constructor: JsObject::new(Object::default()),
54 prototype: JsObject::new(prototype),
55 }
56 }
57
58 #[inline]
62 pub fn constructor(&self) -> JsObject {
63 self.constructor.clone()
64 }
65
66 #[inline]
70 pub fn prototype(&self) -> JsObject {
71 self.prototype.clone()
72 }
73}
74
75#[derive(Debug, Clone)]
77pub struct StandardObjects {
78 object: StandardConstructor,
79 function: StandardConstructor,
80 array: StandardConstructor,
81 bigint: StandardConstructor,
82 number: StandardConstructor,
83 boolean: StandardConstructor,
84 string: StandardConstructor,
85 regexp: StandardConstructor,
86 symbol: StandardConstructor,
87 error: StandardConstructor,
88 type_error: StandardConstructor,
89 referece_error: StandardConstructor,
90 range_error: StandardConstructor,
91 syntax_error: StandardConstructor,
92 eval_error: StandardConstructor,
93 uri_error: StandardConstructor,
94 map: StandardConstructor,
95 set: StandardConstructor,
96}
97
98impl Default for StandardObjects {
99 fn default() -> Self {
100 Self {
101 object: StandardConstructor::default(),
102 function: StandardConstructor::default(),
103 array: StandardConstructor::default(),
104 bigint: StandardConstructor::default(),
105 number: StandardConstructor::with_prototype(Object::number(0.0)),
106 boolean: StandardConstructor::with_prototype(Object::boolean(false)),
107 string: StandardConstructor::with_prototype(Object::string("")),
108 regexp: StandardConstructor::default(),
109 symbol: StandardConstructor::default(),
110 error: StandardConstructor::default(),
111 type_error: StandardConstructor::default(),
112 referece_error: StandardConstructor::default(),
113 range_error: StandardConstructor::default(),
114 syntax_error: StandardConstructor::default(),
115 eval_error: StandardConstructor::default(),
116 uri_error: StandardConstructor::default(),
117 map: StandardConstructor::default(),
118 set: StandardConstructor::default(),
119 }
120 }
121}
122
123impl StandardObjects {
124 #[inline]
125 pub fn object_object(&self) -> &StandardConstructor {
126 &self.object
127 }
128
129 #[inline]
130 pub fn function_object(&self) -> &StandardConstructor {
131 &self.function
132 }
133
134 #[inline]
135 pub fn array_object(&self) -> &StandardConstructor {
136 &self.array
137 }
138
139 #[inline]
140 pub fn bigint_object(&self) -> &StandardConstructor {
141 &self.bigint
142 }
143
144 #[inline]
145 pub fn number_object(&self) -> &StandardConstructor {
146 &self.number
147 }
148
149 #[inline]
150 pub fn boolean_object(&self) -> &StandardConstructor {
151 &self.boolean
152 }
153
154 #[inline]
155 pub fn string_object(&self) -> &StandardConstructor {
156 &self.string
157 }
158
159 #[inline]
160 pub fn regexp_object(&self) -> &StandardConstructor {
161 &self.regexp
162 }
163
164 #[inline]
165 pub fn symbol_object(&self) -> &StandardConstructor {
166 &self.symbol
167 }
168
169 #[inline]
170 pub fn error_object(&self) -> &StandardConstructor {
171 &self.error
172 }
173
174 #[inline]
175 pub fn reference_error_object(&self) -> &StandardConstructor {
176 &self.referece_error
177 }
178
179 #[inline]
180 pub fn type_error_object(&self) -> &StandardConstructor {
181 &self.type_error
182 }
183
184 #[inline]
185 pub fn range_error_object(&self) -> &StandardConstructor {
186 &self.range_error
187 }
188
189 #[inline]
190 pub fn syntax_error_object(&self) -> &StandardConstructor {
191 &self.syntax_error
192 }
193
194 #[inline]
195 pub fn eval_error_object(&self) -> &StandardConstructor {
196 &self.eval_error
197 }
198
199 #[inline]
200 pub fn uri_error_object(&self) -> &StandardConstructor {
201 &self.uri_error
202 }
203
204 #[inline]
205 pub fn map_object(&self) -> &StandardConstructor {
206 &self.map
207 }
208
209 #[inline]
210 pub fn set_object(&self) -> &StandardConstructor {
211 &self.set
212 }
213}
214
215#[derive(Debug, Copy, Clone)]
217pub(crate) enum StrictType {
218 Off,
219 Global,
220 Function,
221}
222
223#[derive(Debug)]
265pub struct Context {
266 pub(crate) realm: Realm,
268
269 executor: Interpreter,
271
272 #[cfg(feature = "console")]
274 console: Console,
275
276 iterator_prototypes: IteratorPrototypes,
278
279 standard_objects: StandardObjects,
281
282 pub trace: bool,
284
285 strict: StrictType,
287}
288
289impl Default for Context {
290 fn default() -> Self {
291 let realm = Realm::create();
292 let executor = Interpreter::new();
293 let mut context = Self {
294 realm,
295 executor,
296 #[cfg(feature = "console")]
297 console: Console::default(),
298 iterator_prototypes: IteratorPrototypes::default(),
299 standard_objects: Default::default(),
300 trace: false,
301 strict: StrictType::Off,
302 };
303
304 context.create_intrinsics();
308 context.iterator_prototypes = IteratorPrototypes::init(&mut context);
309 context
310 }
311}
312
313impl Context {
314 #[inline]
316 pub fn new() -> Self {
317 Default::default()
318 }
319
320 #[inline]
321 pub fn executor(&mut self) -> &mut Interpreter {
322 &mut self.executor
323 }
324
325 #[cfg(feature = "console")]
327 pub(crate) fn console(&self) -> &Console {
328 &self.console
329 }
330
331 #[cfg(feature = "console")]
333 #[inline]
334 pub(crate) fn console_mut(&mut self) -> &mut Console {
335 &mut self.console
336 }
337
338 #[inline]
340 pub fn strict(&self) -> bool {
341 matches!(self.strict, StrictType::Global | StrictType::Function)
342 }
343
344 #[inline]
346 pub(crate) fn strict_type(&self) -> StrictType {
347 self.strict
348 }
349
350 #[inline]
352 pub(crate) fn set_strict(&mut self, strict: StrictType) {
353 self.strict = strict;
354 }
355
356 #[inline]
358 pub fn set_strict_mode_off(&mut self) {
359 self.strict = StrictType::Off;
360 }
361
362 #[inline]
364 pub fn set_strict_mode_global(&mut self) {
365 self.strict = StrictType::Global;
366 }
367
368 #[inline]
370 fn create_intrinsics(&mut self) {
371 let _timer = BoaProfiler::global().start_event("create_intrinsics", "interpreter");
372 builtins::init(self);
374 }
375
376 #[inline]
378 pub fn construct_object(&self) -> JsObject {
379 let object_prototype: JsValue = self.standard_objects().object_object().prototype().into();
380 JsObject::new(Object::create(object_prototype))
381 }
382
383 #[inline]
385 pub(crate) fn call(
386 &mut self,
387 f: &JsValue,
388 this: &JsValue,
389 args: &[JsValue],
390 ) -> JsResult<JsValue> {
391 match *f {
392 JsValue::Object(ref object) => object.call(this, args, self),
393 _ => self.throw_type_error("not a function"),
394 }
395 }
396
397 #[inline]
399 pub fn global_object(&self) -> JsObject {
400 self.realm.global_object.clone()
401 }
402
403 #[inline]
405 pub fn construct_error<M>(&mut self, message: M) -> JsValue
406 where
407 M: Into<Box<str>>,
408 {
409 New::from(Call::new(
411 Identifier::from("Error"),
412 vec![Const::from(message.into()).into()],
413 ))
414 .run(self)
415 .expect("Into<String> used as message")
416 }
417
418 #[inline]
420 pub fn throw_error<M>(&mut self, message: M) -> JsResult<JsValue>
421 where
422 M: Into<Box<str>>,
423 {
424 Err(self.construct_error(message))
425 }
426
427 #[inline]
429 pub fn construct_range_error<M>(&mut self, message: M) -> JsValue
430 where
431 M: Into<Box<str>>,
432 {
433 New::from(Call::new(
435 Identifier::from("RangeError"),
436 vec![Const::from(message.into()).into()],
437 ))
438 .run(self)
439 .expect("Into<String> used as message")
440 }
441
442 #[inline]
444 pub fn throw_range_error<M>(&mut self, message: M) -> JsResult<JsValue>
445 where
446 M: Into<Box<str>>,
447 {
448 Err(self.construct_range_error(message))
449 }
450
451 #[inline]
453 pub fn construct_type_error<M>(&mut self, message: M) -> JsValue
454 where
455 M: Into<Box<str>>,
456 {
457 New::from(Call::new(
459 Identifier::from("TypeError"),
460 vec![Const::from(message.into()).into()],
461 ))
462 .run(self)
463 .expect("Into<String> used as message")
464 }
465
466 #[inline]
468 pub fn throw_type_error<M>(&mut self, message: M) -> JsResult<JsValue>
469 where
470 M: Into<Box<str>>,
471 {
472 Err(self.construct_type_error(message))
473 }
474
475 #[inline]
477 pub fn construct_reference_error<M>(&mut self, message: M) -> JsValue
478 where
479 M: Into<Box<str>>,
480 {
481 New::from(Call::new(
482 Identifier::from("ReferenceError"),
483 vec![Const::from(message.into()).into()],
484 ))
485 .run(self)
486 .expect("Into<String> used as message")
487 }
488
489 #[inline]
491 pub fn throw_reference_error<M>(&mut self, message: M) -> JsResult<JsValue>
492 where
493 M: Into<Box<str>>,
494 {
495 Err(self.construct_reference_error(message))
496 }
497
498 #[inline]
500 pub fn construct_syntax_error<M>(&mut self, message: M) -> JsValue
501 where
502 M: Into<Box<str>>,
503 {
504 New::from(Call::new(
505 Identifier::from("SyntaxError"),
506 vec![Const::from(message.into()).into()],
507 ))
508 .run(self)
509 .expect("Into<String> used as message")
510 }
511
512 #[inline]
514 pub fn throw_syntax_error<M>(&mut self, message: M) -> JsResult<JsValue>
515 where
516 M: Into<Box<str>>,
517 {
518 Err(self.construct_syntax_error(message))
519 }
520
521 pub fn construct_eval_error<M>(&mut self, message: M) -> JsValue
523 where
524 M: Into<Box<str>>,
525 {
526 New::from(Call::new(
527 Identifier::from("EvalError"),
528 vec![Const::from(message.into()).into()],
529 ))
530 .run(self)
531 .expect("Into<String> used as message")
532 }
533
534 pub fn construct_uri_error<M>(&mut self, message: M) -> JsValue
536 where
537 M: Into<Box<str>>,
538 {
539 New::from(Call::new(
540 Identifier::from("URIError"),
541 vec![Const::from(message.into()).into()],
542 ))
543 .run(self)
544 .expect("Into<String> used as message")
545 }
546
547 pub fn throw_eval_error<M>(&mut self, message: M) -> JsResult<JsValue>
549 where
550 M: Into<Box<str>>,
551 {
552 Err(self.construct_eval_error(message))
553 }
554
555 pub fn throw_uri_error<M>(&mut self, message: M) -> JsResult<JsValue>
557 where
558 M: Into<Box<str>>,
559 {
560 Err(self.construct_uri_error(message))
561 }
562
563 pub(crate) fn create_function<N, P>(
565 &mut self,
566 name: N,
567 params: P,
568 mut body: StatementList,
569 flags: FunctionFlags,
570 ) -> JsResult<JsValue>
571 where
572 N: Into<JsString>,
573 P: Into<Box<[FormalParameter]>>,
574 {
575 let name = name.into();
576 let function_prototype: JsValue =
577 self.standard_objects().function_object().prototype().into();
578
579 let prototype = self.construct_object();
581
582 if self.strict() {
584 body.set_strict(true);
585 }
586
587 let params = params.into();
588 let params_len = params.len();
589 let func = Function::Ordinary {
590 flags,
591 body: RcStatementList::from(body),
592 params,
593 environment: self.get_current_environment().clone(),
594 };
595
596 let function = JsObject::new(Object::function(func, function_prototype));
597
598 let constructor = PropertyDescriptor::builder()
600 .value(function.clone())
601 .writable(true)
602 .enumerable(false)
603 .configurable(true);
604 prototype.define_property_or_throw("constructor", constructor, self)?;
605
606 let prototype = PropertyDescriptor::builder()
607 .value(prototype)
608 .writable(true)
609 .enumerable(false)
610 .configurable(false);
611 function.define_property_or_throw(PROTOTYPE, prototype, self)?;
612
613 let length = PropertyDescriptor::builder()
614 .value(params_len)
615 .writable(false)
616 .enumerable(false)
617 .configurable(true);
618 function.define_property_or_throw("length", length, self)?;
619
620 let name = PropertyDescriptor::builder()
621 .value(name)
622 .writable(false)
623 .enumerable(false)
624 .configurable(true);
625 function.define_property_or_throw("name", name, self)?;
626
627 Ok(function.into())
628 }
629
630 #[inline]
646 pub fn register_global_function(
647 &mut self,
648 name: &str,
649 length: usize,
650 body: NativeFunction,
651 ) -> JsResult<()> {
652 let function = FunctionBuilder::native(self, body)
653 .name(name)
654 .length(length)
655 .constructable(true)
656 .build();
657
658 self.global_object().insert_property(
659 name,
660 PropertyDescriptor::builder()
661 .value(function)
662 .writable(true)
663 .enumerable(false)
664 .configurable(true),
665 );
666 Ok(())
667 }
668
669 #[inline]
691 pub fn register_global_closure<F>(&mut self, name: &str, length: usize, body: F) -> JsResult<()>
692 where
693 F: Fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue> + Copy + 'static,
694 {
695 let function = FunctionBuilder::closure(self, body)
696 .name(name)
697 .length(length)
698 .constructable(true)
699 .build();
700
701 self.global_object().insert_property(
702 name,
703 PropertyDescriptor::builder()
704 .value(function)
705 .writable(true)
706 .enumerable(false)
707 .configurable(true),
708 );
709 Ok(())
710 }
711
712 #[inline]
714 pub(crate) fn has_property(&mut self, obj: &JsValue, key: &PropertyKey) -> JsResult<bool> {
715 if let Some(obj) = obj.as_object() {
716 obj.__has_property__(key, self)
717 } else {
718 Ok(false)
719 }
720 }
721
722 #[inline]
723 pub(crate) fn set_value(&mut self, node: &Node, value: JsValue) -> JsResult<JsValue> {
724 match node {
725 Node::Identifier(ref name) => {
726 self.set_mutable_binding(name.as_ref(), value.clone(), true)?;
727 Ok(value)
728 }
729 Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node
730 .obj()
731 .run(self)?
732 .set_field(get_const_field_node.field(), value, false, self)?),
733 Node::GetField(ref get_field) => {
734 let field = get_field.field().run(self)?;
735 let key = field.to_property_key(self)?;
736 Ok(get_field
737 .obj()
738 .run(self)?
739 .set_field(key, value, false, self)?)
740 }
741 _ => self.throw_type_error(format!("invalid assignment to {}", node)),
742 }
743 }
744
745 #[inline]
759 pub fn register_global_class<T>(&mut self) -> JsResult<()>
760 where
761 T: Class,
762 {
763 let mut class_builder = ClassBuilder::new::<T>(self);
764 T::init(&mut class_builder)?;
765
766 let class = class_builder.build();
767 let property = PropertyDescriptor::builder()
768 .value(class)
769 .writable(T::ATTRIBUTES.writable())
770 .enumerable(T::ATTRIBUTES.enumerable())
771 .configurable(T::ATTRIBUTES.configurable());
772 self.global_object().insert(T::NAME, property);
773 Ok(())
774 }
775
776 #[inline]
809 pub fn register_global_property<K, V>(&mut self, key: K, value: V, attribute: Attribute)
810 where
811 K: Into<PropertyKey>,
812 V: Into<JsValue>,
813 {
814 self.global_object().insert(
815 key,
816 PropertyDescriptor::builder()
817 .value(value)
818 .writable(attribute.writable())
819 .enumerable(attribute.enumerable())
820 .configurable(attribute.configurable()),
821 );
822 }
823
824 #[cfg(not(feature = "vm"))]
837 #[allow(clippy::unit_arg, clippy::drop_copy)]
838 #[inline]
839 pub fn eval<T: AsRef<[u8]>>(&mut self, src: T) -> JsResult<JsValue> {
840 let main_timer = BoaProfiler::global().start_event("Main", "Main");
841 let src_bytes: &[u8] = src.as_ref();
842
843 let parsing_result = Parser::new(src_bytes, false)
844 .parse_all()
845 .map_err(|e| e.to_string());
846
847 let execution_result = match parsing_result {
848 Ok(statement_list) => {
849 if statement_list.strict() {
850 self.set_strict_mode_global();
851 }
852 statement_list.run(self)
853 }
854 Err(e) => self.throw_syntax_error(e),
855 };
856
857 drop(main_timer);
859 BoaProfiler::global().drop();
860
861 execution_result
862 }
863
864 #[cfg(feature = "vm")]
877 #[allow(clippy::unit_arg, clippy::drop_copy)]
878 pub fn eval<T: AsRef<[u8]>>(&mut self, src: T) -> JsResult<JsValue> {
879 let main_timer = BoaProfiler::global().start_event("Main", "Main");
880 let src_bytes: &[u8] = src.as_ref();
881
882 let parsing_result = Parser::new(src_bytes, false)
883 .parse_all()
884 .map_err(|e| e.to_string());
885
886 let statement_list = match parsing_result {
887 Ok(statement_list) => statement_list,
888 Err(e) => return self.throw_syntax_error(e),
889 };
890
891 let mut compiler = crate::bytecompiler::ByteCompiler::default();
892 compiler.compile_statement_list(&statement_list, true);
893 let code_block = compiler.finish();
894 let mut vm = Vm::new(code_block, self);
895 let result = vm.run();
896
897 drop(main_timer);
899 BoaProfiler::global().drop();
900
901 result
902 }
903
904 #[inline]
906 pub fn iterator_prototypes(&self) -> &IteratorPrototypes {
907 &self.iterator_prototypes
908 }
909
910 #[inline]
912 pub fn standard_objects(&self) -> &StandardObjects {
913 &self.standard_objects
914 }
915
916 pub fn set_trace(&mut self, trace: bool) {
918 self.trace = trace;
919 }
920}