1use crate::host::HostFunction;
2use crate::object::object::JSObject;
3use crate::runtime::context::JSContext;
4use crate::value::JSValue;
5
6fn set_ctor_prototype(obj: &mut JSObject, key: crate::runtime::atom::Atom, val: JSValue) {
7 obj.define_property(
8 key,
9 crate::object::object::PropertyDescriptor {
10 value: Some(val),
11 writable: false,
12 enumerable: false,
13 configurable: false,
14 get: None,
15 set: None,
16 },
17 );
18}
19
20fn set_own_ne(obj: &mut JSObject, key: crate::runtime::atom::Atom, val: JSValue) {
21 obj.define_property(
22 key,
23 crate::object::object::PropertyDescriptor {
24 value: Some(val),
25 writable: true,
26 enumerable: false,
27 configurable: true,
28 get: None,
29 set: None,
30 },
31 );
32}
33
34fn create_builtin_function(ctx: &mut JSContext, name: &str) -> JSValue {
35 let arity = ctx.get_builtin_arity(name).unwrap_or(1);
36 let mut func = crate::object::function::JSFunction::new_builtin(ctx.intern(name), arity);
37 func.set_builtin_marker(ctx, name);
38 let ptr = Box::into_raw(Box::new(func)) as usize;
39 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
40 JSValue::new_function(ptr)
41}
42
43pub fn init_error(ctx: &mut JSContext) {
44 fn set_ne(
45 obj: &mut crate::object::object::JSObject,
46 key: crate::runtime::atom::Atom,
47 val: crate::value::JSValue,
48 ) {
49 obj.define_property(
50 key,
51 crate::object::object::PropertyDescriptor {
52 value: Some(val),
53 writable: true,
54 enumerable: false,
55 configurable: true,
56 get: None,
57 set: None,
58 },
59 );
60 }
61
62 let error_atom = ctx.intern("Error");
63
64 let mut error_func = crate::object::function::JSFunction::new_builtin(error_atom, 1);
65 error_func.set_builtin_marker(ctx, "error_constructor");
66 if let Some(func_proto) = ctx.get_function_prototype() {
67 error_func.base.prototype = Some(func_proto);
68 }
69 let error_ptr = Box::into_raw(Box::new(error_func)) as usize;
70 ctx.runtime_mut().gc_heap_mut().track_function(error_ptr);
71 let error_value = JSValue::new_function(error_ptr);
72
73 let global = ctx.global();
74 if global.is_object() {
75 let global_obj = global.as_object_mut();
76 crate::builtins::global::set_non_enumerable(global_obj, error_atom, error_value);
77 }
78
79 let mut proto_obj = JSObject::new();
80 set_ne(
81 &mut proto_obj,
82 ctx.intern("name"),
83 JSValue::new_string(ctx.intern("Error")),
84 );
85 set_ne(
86 &mut proto_obj,
87 ctx.intern("message"),
88 JSValue::new_string(ctx.intern("")),
89 );
90 set_ne(
91 &mut proto_obj,
92 ctx.intern("toString"),
93 create_builtin_function(ctx, "error_toString"),
94 );
95
96 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
97 proto_obj.prototype = Some(obj_proto_ptr);
98 }
99
100 set_ne(&mut proto_obj, ctx.intern("constructor"), error_value);
101
102 let proto_ptr = Box::into_raw(Box::new(proto_obj)) as usize;
103 ctx.set_error_prototype(proto_ptr);
104 let proto_value = JSValue::new_object(proto_ptr);
105 if ctx.get_builtin_func("error_constructor").is_some() {
106 let f = unsafe { JSValue::function_from_ptr_mut(error_ptr) };
107 set_ctor_prototype(&mut f.base, ctx.intern("prototype"), proto_value);
108 }
109
110 let proto_atom = ctx.intern("ErrorPrototype");
111 if global.is_object() {
112 let global_obj = global.as_object_mut();
113 crate::builtins::global::set_non_enumerable(global_obj, proto_atom, proto_value);
114 }
115
116 init_type_error(ctx);
117 init_reference_error(ctx);
118 init_syntax_error(ctx);
119 init_range_error(ctx);
120 init_uri_error(ctx);
121 init_eval_error(ctx);
122
123 let global = ctx.global();
124 if global.is_object() {
125 let error_ctor_val = global.as_object().get(error_atom);
126 if let Some(error_ctor) = error_ctor_val {
127 if error_ctor.is_function() {
128 let error_ctor_ptr = error_ctor.get_ptr() as *mut crate::object::object::JSObject;
129 for name in ["TypeError", "ReferenceError", "SyntaxError", "RangeError", "URIError", "EvalError"] {
130 let atom = ctx.intern(name);
131 if let Some(ctor_val) = global.as_object().get(atom) {
132 if ctor_val.is_function() {
133 let ctor = unsafe { JSValue::function_from_ptr_mut(ctor_val.get_ptr()) };
134 ctor.base.set_prototype_raw(error_ctor_ptr);
135 }
136 }
137 }
138 }
139 }
140 }
141}
142
143fn init_type_error(ctx: &mut JSContext) {
144 fn set_ne(
145 obj: &mut crate::object::object::JSObject,
146 key: crate::runtime::atom::Atom,
147 val: crate::value::JSValue,
148 ) {
149 obj.define_property(
150 key,
151 crate::object::object::PropertyDescriptor {
152 value: Some(val),
153 writable: true,
154 enumerable: false,
155 configurable: true,
156 get: None,
157 set: None,
158 },
159 );
160 }
161
162 let atom = ctx.intern("TypeError");
163 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
164 ctor.set_builtin_marker(ctx, "type_error_constructor");
165 if let Some(func_proto) = ctx.get_function_prototype() {
166 ctor.base.prototype = Some(func_proto);
167 }
168 let ptr = Box::into_raw(Box::new(ctor)) as usize;
169 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
170 let value = JSValue::new_function(ptr);
171
172 let global = ctx.global();
173 if global.is_object() {
174 let global_obj = global.as_object_mut();
175 crate::builtins::global::set_non_enumerable(global_obj, atom, value);
176 }
177
178 let mut proto = JSObject::new();
179 set_ne(
180 &mut proto,
181 ctx.intern("name"),
182 JSValue::new_string(ctx.intern("TypeError")),
183 );
184 set_ne(
185 &mut proto,
186 ctx.intern("message"),
187 JSValue::new_string(ctx.intern("")),
188 );
189
190 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
191 proto.prototype = Some(error_proto_ptr);
192 }
193 set_ne(&mut proto, ctx.intern("constructor"), value);
194
195 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
196 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
197 let proto_value = JSValue::new_object(proto_ptr);
198 ctx.set_type_error_prototype(proto_ptr);
199 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
200 set_ctor_prototype(&mut ctor.base, ctx.intern("prototype"), proto_value);
201}
202
203fn init_reference_error(ctx: &mut JSContext) {
204 fn set_ne(
205 obj: &mut crate::object::object::JSObject,
206 key: crate::runtime::atom::Atom,
207 val: crate::value::JSValue,
208 ) {
209 obj.define_property(
210 key,
211 crate::object::object::PropertyDescriptor {
212 value: Some(val),
213 writable: true,
214 enumerable: false,
215 configurable: true,
216 get: None,
217 set: None,
218 },
219 );
220 }
221
222 let atom = ctx.intern("ReferenceError");
223 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
224 ctor.set_builtin_marker(ctx, "reference_error_constructor");
225 if let Some(func_proto) = ctx.get_function_prototype() {
226 ctor.base.prototype = Some(func_proto);
227 }
228 let ptr = Box::into_raw(Box::new(ctor)) as usize;
229 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
230 let value = JSValue::new_function(ptr);
231
232 let mut proto = JSObject::new();
233 set_ne(
234 &mut proto,
235 ctx.intern("name"),
236 JSValue::new_string(ctx.intern("ReferenceError")),
237 );
238 set_ne(
239 &mut proto,
240 ctx.intern("message"),
241 JSValue::new_string(ctx.intern("")),
242 );
243 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
244 proto.prototype = Some(error_proto_ptr);
245 }
246 set_ne(&mut proto, ctx.intern("constructor"), value);
247
248 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
249 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
250 let proto_value = JSValue::new_object(proto_ptr);
251 ctx.set_reference_error_prototype(proto_ptr);
252 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
253 set_ctor_prototype(&mut ctor.base, ctx.intern("prototype"), proto_value);
254
255 let global = ctx.global();
256 if global.is_object() {
257 let global_obj = global.as_object_mut();
258 crate::builtins::global::set_non_enumerable(global_obj, atom, value);
259 }
260}
261
262fn init_syntax_error(ctx: &mut JSContext) {
263 fn set_ne(
264 obj: &mut crate::object::object::JSObject,
265 key: crate::runtime::atom::Atom,
266 val: crate::value::JSValue,
267 ) {
268 obj.define_property(
269 key,
270 crate::object::object::PropertyDescriptor {
271 value: Some(val),
272 writable: true,
273 enumerable: false,
274 configurable: true,
275 get: None,
276 set: None,
277 },
278 );
279 }
280
281 let atom = ctx.intern("SyntaxError");
282 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
283 ctor.set_builtin_marker(ctx, "syntax_error_constructor");
284 if let Some(func_proto) = ctx.get_function_prototype() {
285 ctor.base.prototype = Some(func_proto);
286 }
287 let ptr = Box::into_raw(Box::new(ctor)) as usize;
288 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
289 let value = JSValue::new_function(ptr);
290
291 let mut proto = JSObject::new();
292 set_ne(
293 &mut proto,
294 ctx.intern("name"),
295 JSValue::new_string(ctx.intern("SyntaxError")),
296 );
297 set_ne(
298 &mut proto,
299 ctx.intern("message"),
300 JSValue::new_string(ctx.intern("")),
301 );
302 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
303 proto.prototype = Some(error_proto_ptr);
304 }
305 set_ne(&mut proto, ctx.intern("constructor"), value);
306
307 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
308 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
309 let proto_value = JSValue::new_object(proto_ptr);
310 ctx.set_syntax_error_prototype(proto_ptr);
311 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
312 set_ctor_prototype(&mut ctor.base, ctx.intern("prototype"), proto_value);
313
314 let global = ctx.global();
315 if global.is_object() {
316 let global_obj = global.as_object_mut();
317 crate::builtins::global::set_non_enumerable(global_obj, atom, value);
318 }
319}
320
321fn init_range_error(ctx: &mut JSContext) {
322 fn set_ne(
323 obj: &mut crate::object::object::JSObject,
324 key: crate::runtime::atom::Atom,
325 val: crate::value::JSValue,
326 ) {
327 obj.define_property(
328 key,
329 crate::object::object::PropertyDescriptor {
330 value: Some(val),
331 writable: true,
332 enumerable: false,
333 configurable: true,
334 get: None,
335 set: None,
336 },
337 );
338 }
339
340 let atom = ctx.intern("RangeError");
341 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
342 ctor.set_builtin_marker(ctx, "range_error_constructor");
343 if let Some(func_proto) = ctx.get_function_prototype() {
344 ctor.base.prototype = Some(func_proto);
345 }
346 let ptr = Box::into_raw(Box::new(ctor)) as usize;
347 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
348 let value = JSValue::new_function(ptr);
349
350 let mut proto = JSObject::new();
351 set_ne(
352 &mut proto,
353 ctx.intern("name"),
354 JSValue::new_string(ctx.intern("RangeError")),
355 );
356 set_ne(
357 &mut proto,
358 ctx.intern("message"),
359 JSValue::new_string(ctx.intern("")),
360 );
361 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
362 proto.prototype = Some(error_proto_ptr);
363 }
364 set_ne(&mut proto, ctx.intern("constructor"), value);
365
366 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
367 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
368 let proto_value = JSValue::new_object(proto_ptr);
369 ctx.set_range_error_prototype(proto_ptr);
370 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
371 set_ctor_prototype(&mut ctor.base, ctx.intern("prototype"), proto_value);
372
373 let global = ctx.global();
374 if global.is_object() {
375 let global_obj = global.as_object_mut();
376 crate::builtins::global::set_non_enumerable(global_obj, atom, value);
377 }
378}
379
380fn init_uri_error(ctx: &mut JSContext) {
381 fn set_ne(
382 obj: &mut crate::object::object::JSObject,
383 key: crate::runtime::atom::Atom,
384 val: crate::value::JSValue,
385 ) {
386 obj.define_property(
387 key,
388 crate::object::object::PropertyDescriptor {
389 value: Some(val),
390 writable: true,
391 enumerable: false,
392 configurable: true,
393 get: None,
394 set: None,
395 },
396 );
397 }
398
399 let atom = ctx.intern("URIError");
400 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
401 ctor.set_builtin_marker(ctx, "uri_error_constructor");
402 if let Some(func_proto) = ctx.get_function_prototype() {
403 ctor.base.prototype = Some(func_proto);
404 }
405 let ptr = Box::into_raw(Box::new(ctor)) as usize;
406 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
407 let value = JSValue::new_function(ptr);
408
409 let global = ctx.global();
410 if global.is_object() {
411 let global_obj = global.as_object_mut();
412 crate::builtins::global::set_non_enumerable(global_obj, atom, value);
413 }
414
415 let mut proto = JSObject::new();
416 set_ne(
417 &mut proto,
418 ctx.intern("name"),
419 JSValue::new_string(ctx.intern("URIError")),
420 );
421 set_ne(
422 &mut proto,
423 ctx.intern("message"),
424 JSValue::new_string(ctx.intern("")),
425 );
426
427 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
428 proto.prototype = Some(error_proto_ptr);
429 }
430 set_ne(&mut proto, ctx.intern("constructor"), value);
431
432 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
433 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
434 let proto_value = JSValue::new_object(proto_ptr);
435 ctx.set_uri_error_prototype(proto_ptr);
436 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
437 set_ctor_prototype(&mut ctor.base, ctx.intern("prototype"), proto_value);
438}
439
440fn init_eval_error(ctx: &mut JSContext) {
441 fn set_ne(
442 obj: &mut crate::object::object::JSObject,
443 key: crate::runtime::atom::Atom,
444 val: crate::value::JSValue,
445 ) {
446 obj.define_property(
447 key,
448 crate::object::object::PropertyDescriptor {
449 value: Some(val),
450 writable: true,
451 enumerable: false,
452 configurable: true,
453 get: None,
454 set: None,
455 },
456 );
457 }
458
459 let atom = ctx.intern("EvalError");
460 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
461 ctor.set_builtin_marker(ctx, "eval_error_constructor");
462 if let Some(func_proto) = ctx.get_function_prototype() {
463 ctor.base.prototype = Some(func_proto);
464 }
465 let ptr = Box::into_raw(Box::new(ctor)) as usize;
466 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
467 let value = JSValue::new_function(ptr);
468
469 let global = ctx.global();
470 if global.is_object() {
471 let global_obj = global.as_object_mut();
472 crate::builtins::global::set_non_enumerable(global_obj, atom, value);
473 }
474
475 let mut proto = JSObject::new();
476 set_ne(
477 &mut proto,
478 ctx.intern("name"),
479 JSValue::new_string(ctx.intern("EvalError")),
480 );
481 set_ne(
482 &mut proto,
483 ctx.intern("message"),
484 JSValue::new_string(ctx.intern("")),
485 );
486
487 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
488 proto.prototype = Some(error_proto_ptr);
489 }
490 set_ne(&mut proto, ctx.intern("constructor"), value);
491
492 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
493 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
494 let proto_value = JSValue::new_object(proto_ptr);
495 ctx.set_eval_error_prototype(proto_ptr);
496 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
497 set_ctor_prototype(&mut ctor.base, ctx.intern("prototype"), proto_value);
498}
499
500fn get_property(
501 ctx: &mut JSContext,
502 obj: &crate::object::object::JSObject,
503 prop: crate::runtime::atom::Atom,
504 this: &JSValue,
505) -> Option<JSValue> {
506 if let Some(val) = obj.get_own_accessor_value(prop) {
507 if val.is_function() {
508 if let Some(vm_ptr) = ctx.get_register_vm_ptr() {
509 let vm = unsafe { &mut *(vm_ptr as *mut crate::runtime::vm::VM) };
510 let saved_exception = ctx.pending_exception.take();
511 let result = vm.call_function_with_this(ctx, val, this.clone(), &[]);
512 if result.is_err() {
513 let exc = ctx
514 .pending_exception
515 .take()
516 .or_else(|| vm.last_caught_exception.take())
517 .or(saved_exception);
518 if let Some(e) = exc {
519 ctx.pending_exception = Some(e);
520 }
521 return None;
522 }
523 ctx.pending_exception = saved_exception;
524 return result.ok();
525 }
526 }
527 return Some(val);
528 }
529 obj.get(prop)
530}
531
532fn js_to_string_value(ctx: &mut JSContext, val: &JSValue) -> Result<String, ()> {
533 if val.is_string() {
534 return Ok(ctx.get_atom_str(val.get_atom()).to_string());
535 }
536 if val.is_undefined() {
537 return Ok("undefined".to_string());
538 }
539 if val.is_null() {
540 return Ok("null".to_string());
541 }
542 if val.is_bool() {
543 if val.is_truthy() {
544 return Ok("true".to_string());
545 }
546 return Ok("false".to_string());
547 }
548 if val.is_int() {
549 let n = val.get_int();
550 return Ok(format!("{}", n));
551 }
552 if val.is_float() {
553 let n = val.to_number();
554 if n == n.floor() && n.is_finite() && n.abs() < 1e15 {
555 return Ok(format!("{}", n as i64));
556 }
557 return Ok(format!("{}", n));
558 }
559 if val.is_symbol() {
560 let mut err = JSObject::new_typed(crate::object::object::ObjectType::Error);
561 if let Some(proto) = ctx.get_type_error_prototype() {
562 err.prototype = Some(proto);
563 }
564 err.set(
565 ctx.common_atoms.message,
566 JSValue::new_string(ctx.intern("Cannot convert a Symbol value to a string")),
567 );
568 let ptr = Box::into_raw(Box::new(err)) as usize;
569 ctx.runtime_mut().gc_heap_mut().track(ptr);
570 ctx.pending_exception = Some(JSValue::new_object(ptr));
571 return Err(());
572 }
573 if val.is_object() {
574 let obj = val.as_object();
575 if let Some(vm_ptr) = ctx.get_register_vm_ptr() {
576 let vm = unsafe { &mut *(vm_ptr as *mut crate::runtime::vm::VM) };
577 let to_string_atom = ctx.intern("toString");
578 let value_of_atom = ctx.intern("valueOf");
579 let hint_string = ctx.intern("string");
580 if let Some(to_prim) = obj.get(ctx.intern("__toPrimitive__hook__")) {
581 let _ = obj;
582 if to_prim.is_function() {
583 let result = vm.call_function_with_this(
584 ctx,
585 to_prim,
586 val.clone(),
587 &[JSValue::new_string(hint_string)],
588 );
589 if ctx.pending_exception.is_some() {
590 return Err(());
591 }
592 if let Ok(prim) = result {
593 if !prim.is_object() {
594 return js_to_string_value(ctx, &prim);
595 }
596 }
597 }
598 }
599 let to_string_fn = obj.get(to_string_atom);
600 let _ = obj;
601 if let Some(fn_val) = to_string_fn {
602 if fn_val.is_function() {
603 let result = vm.call_function_with_this(ctx, fn_val, val.clone(), &[]);
604 if ctx.pending_exception.is_some() {
605 return Err(());
606 }
607 if let Ok(r) = result {
608 if !r.is_object() {
609 return js_to_string_value(ctx, &r);
610 }
611 }
612 }
613 }
614 if ctx.pending_exception.is_some() {
615 return Err(());
616 }
617 let obj2 = val.as_object();
618 let value_of_fn = obj2.get(value_of_atom);
619 let _ = obj2;
620 if let Some(fn_val) = value_of_fn {
621 if fn_val.is_function() {
622 let result = vm.call_function_with_this(ctx, fn_val, val.clone(), &[]);
623 if ctx.pending_exception.is_some() {
624 return Err(());
625 }
626 if let Ok(r) = result {
627 if !r.is_object() {
628 return js_to_string_value(ctx, &r);
629 }
630 }
631 }
632 }
633 if ctx.pending_exception.is_some() {
634 return Err(());
635 }
636 }
637 let mut err = JSObject::new_typed(crate::object::object::ObjectType::Error);
638 if let Some(proto) = ctx.get_type_error_prototype() {
639 err.prototype = Some(proto);
640 }
641 err.set(
642 ctx.common_atoms.message,
643 JSValue::new_string(ctx.intern("Cannot convert object to primitive value")),
644 );
645 let ptr = Box::into_raw(Box::new(err)) as usize;
646 ctx.runtime_mut().gc_heap_mut().track(ptr);
647 ctx.pending_exception = Some(JSValue::new_object(ptr));
648 return Err(());
649 }
650 Ok(String::new())
651}
652
653fn build_error(
654 ctx: &mut JSContext,
655 name: &str,
656 args: &[JSValue],
657 proto: Option<*mut JSObject>,
658) -> JSValue {
659 let mut err = JSObject::new_typed(crate::object::object::ObjectType::Error);
660 set_own_ne(
661 &mut err,
662 ctx.intern("name"),
663 JSValue::new_string(ctx.intern(name)),
664 );
665 if !args.is_empty() && !args[0].is_undefined() {
666 match js_to_string_value(ctx, &args[0]) {
667 Ok(s) => {
668 set_own_ne(
669 &mut err,
670 ctx.intern("message"),
671 JSValue::new_string(ctx.intern(&s)),
672 );
673 }
674 Err(()) => return JSValue::undefined(),
675 }
676 }
677 if args.len() > 1 && args[1].is_object() {
678 let cause_atom = ctx.intern("cause");
679 let opts_this = args[1];
680 let opts = opts_this.as_object();
681 let cause = get_property(ctx, opts, cause_atom, &opts_this);
682 let _ = opts;
683 if let Some(cause) = cause {
684 set_own_ne(&mut err, cause_atom, cause);
685 }
686 }
687 if let Some(p) = proto {
688 err.prototype = Some(p);
689 }
690 let ptr = Box::into_raw(Box::new(err)) as usize;
691 ctx.runtime_mut().gc_heap_mut().track(ptr);
692 JSValue::new_object(ptr)
693}
694
695pub fn error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
696 let proto = ctx.get_error_prototype().map(|p| p as *mut _);
697 build_error(ctx, "Error", args, proto)
698}
699
700pub fn type_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
701 let proto = ctx.get_type_error_prototype().map(|p| p as *mut _);
702 build_error(ctx, "TypeError", args, proto)
703}
704
705pub fn reference_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
706 let proto = ctx
707 .get_reference_error_prototype()
708 .or_else(|| ctx.get_error_prototype())
709 .map(|p| p as *mut _);
710 build_error(ctx, "ReferenceError", args, proto)
711}
712
713pub fn syntax_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
714 let proto = ctx.get_syntax_error_prototype().map(|p| p as *mut _);
715 build_error(ctx, "SyntaxError", args, proto)
716}
717
718pub fn range_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
719 let proto = ctx
720 .get_range_error_prototype()
721 .or_else(|| ctx.get_error_prototype())
722 .map(|p| p as *mut _);
723 build_error(ctx, "RangeError", args, proto)
724}
725
726pub fn uri_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
727 let proto = ctx
728 .get_uri_error_prototype()
729 .or_else(|| ctx.get_error_prototype())
730 .map(|p| p as *mut _);
731 build_error(ctx, "URIError", args, proto)
732}
733
734pub fn eval_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
735 let proto = ctx
736 .get_eval_error_prototype()
737 .or_else(|| ctx.get_error_prototype())
738 .map(|p| p as *mut _);
739 build_error(ctx, "EvalError", args, proto)
740}
741
742fn error_to_string(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
743 if args.is_empty() {
744 let mut err =
745 crate::object::object::JSObject::new_typed(crate::object::object::ObjectType::Error);
746 if let Some(proto) = ctx.get_type_error_prototype() {
747 err.prototype = Some(proto);
748 }
749 err.set(
750 ctx.common_atoms.message,
751 JSValue::new_string(ctx.intern("Error.prototype.toString called on undefined")),
752 );
753 let ptr = Box::into_raw(Box::new(err)) as usize;
754 ctx.runtime_mut().gc_heap_mut().track(ptr);
755 ctx.pending_exception = Some(JSValue::new_object(ptr));
756 return JSValue::undefined();
757 }
758 let this = &args[0];
759 if !this.is_object() {
760 let mut err =
761 crate::object::object::JSObject::new_typed(crate::object::object::ObjectType::Error);
762 if let Some(proto) = ctx.get_type_error_prototype() {
763 err.prototype = Some(proto);
764 }
765 err.set(
766 ctx.common_atoms.message,
767 JSValue::new_string(ctx.intern("Error.prototype.toString called on non-object")),
768 );
769 let ptr = Box::into_raw(Box::new(err)) as usize;
770 ctx.runtime_mut().gc_heap_mut().track(ptr);
771 ctx.pending_exception = Some(JSValue::new_object(ptr));
772 return JSValue::undefined();
773 }
774
775 let obj = this.as_object();
776 let name_atom = ctx.intern("name");
777 let name_val = get_property(ctx, &obj, name_atom, this);
778 let _ = obj;
779 if ctx.pending_exception.is_some() {
780 return JSValue::undefined();
781 }
782 let name: Result<String, ()> = match name_val {
783 Some(n) => {
784 if n.is_undefined() {
785 Ok("Error".to_string())
786 } else {
787 match js_to_string_value(ctx, &n) {
788 Ok(s) => Ok(s),
789 Err(()) => return JSValue::undefined(),
790 }
791 }
792 }
793 None => Ok("Error".to_string()),
794 };
795 if ctx.pending_exception.is_some() {
796 return JSValue::undefined();
797 }
798
799 let obj2 = this.as_object();
800 let msg_atom = ctx.intern("message");
801 let message_val = get_property(ctx, &obj2, msg_atom, this);
802 let _ = obj2;
803 if ctx.pending_exception.is_some() {
804 return JSValue::undefined();
805 }
806 let message: Result<String, ()> = match message_val {
807 Some(m) => {
808 if m.is_undefined() {
809 Ok(String::new())
810 } else {
811 match js_to_string_value(ctx, &m) {
812 Ok(s) => Ok(s),
813 Err(()) => return JSValue::undefined(),
814 }
815 }
816 }
817 None => Ok(String::new()),
818 };
819
820 match (name, message) {
821 (Ok(n), Ok(m)) => {
822 if n.is_empty() {
823 JSValue::new_string(ctx.intern(&m))
824 } else if m.is_empty() {
825 JSValue::new_string(ctx.intern(&n))
826 } else {
827 JSValue::new_string(ctx.intern(&format!("{}: {}", n, m)))
828 }
829 }
830 _ => JSValue::undefined(),
831 }
832}
833
834pub fn register_builtins(ctx: &mut JSContext) {
835 ctx.register_builtin(
836 "error_constructor",
837 HostFunction::ctor("Error", 1, error_constructor),
838 );
839 ctx.register_builtin(
840 "type_error_constructor",
841 HostFunction::ctor("TypeError", 1, type_error_constructor),
842 );
843 ctx.register_builtin(
844 "reference_error_constructor",
845 HostFunction::ctor("ReferenceError", 1, reference_error_constructor),
846 );
847 ctx.register_builtin(
848 "syntax_error_constructor",
849 HostFunction::ctor("SyntaxError", 1, syntax_error_constructor),
850 );
851 ctx.register_builtin(
852 "range_error_constructor",
853 HostFunction::ctor("RangeError", 1, range_error_constructor),
854 );
855 ctx.register_builtin(
856 "uri_error_constructor",
857 HostFunction::ctor("URIError", 1, uri_error_constructor),
858 );
859 ctx.register_builtin(
860 "eval_error_constructor",
861 HostFunction::ctor("EvalError", 1, eval_error_constructor),
862 );
863 ctx.register_builtin(
864 "error_toString",
865 HostFunction::method("toString", 0, error_to_string),
866 );
867}